home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-08-16 | 89.7 KB | 3,490 lines |
- /* kermit/s/manif >> Begin << */
- /*
- * Kermit-GCOS
- *
- * An implementation of the Kermit file transfer protocol for
- * Honeywell GCOS systems.
- *
- * Author: John L. Huxtable
- * University of Kansas Academic Computing Services
- * Lawrence, Kansas 66045
- * HLSUA Site Code: UKAN
- * Date: 03/07/85
- *
- * This is a remote-only Kermit since GCOS cannot originate
- * a connection with another system. It can use either paper-tape
- * mode input or normal input for packets depending on whether
- * or not all ASCII printing characters can be received in normal
- * mode. (The default is +TapeMode). It can transfer text files
- * and with the BYtestream and BItsream format specifications
- * any file on GCOS. Instead of wildcard send Kermit-GCOS contains
- * an indeX file option for specifying a file which contains a list
- * of file names and options for sending. Kermit-GCOS has 8th-bit
- * prefixing and repeat count prefixing. It does not have alternate
- * checksums. It can act as a server with the following remote
- * commands: Bye, CWD, Erase, Finish, Get, Logout, Send, Status
- * and Type. Remote Directory and Remote Space are optionally
- * available, as determined by the values of flags wat_lc and
- * wat_smcl within the EXTRN definitions, below. Commands can
- * be entered on the command line used to invoke Kermit-GCOS or
- * through an interactive prompt mode. A HELP command provides
- * interactive users with limited support information. See the
- * user documentation for more information.
- *
- * For information about obtaining Kermit programs for other
- * systems, contact:
- *
- * KERMIT Distribution
- * Columbia University Center for Computing Activities
- * 7th Floor, Watson Laboratory
- * 612 West 115th Street
- * New York, N.Y. 10025
- */
-
-
- /*
- * MANIF -- Manifests for Kermit.
- */
-
- %b/manif/.bset
- %b/manif/t.drls
-
-
- /*
- * .Bset Options.
- */
-
- OP.FILE = 0;
- OP.QUERY = 1;
- OP.DONE = 2;
- OP.EXIT = 3;
- OP.QUIT = 4;
- OP.HELP = 5;
- OP.RECV = 6;
- OP.SEND = 7;
- OP.SERV = 8;
- OP.SET = 9;
- OP.STAT = 10;
- OP.INDEX = 11;
- OP.FORMAT = 12;
- OP.CHKSUM = 13;
- OP.DEBUG = 14;
- OP.DELAY = 15;
- OP.RANDOM = 16;
- OP.DISCARD = 17;
- OP.RETRY = 18;
- OP.PERM = 19;
- OP.TAPMOD = 20;
- OP.XON = 21;
- OP.OVWRITE = 22;
- OP.SEOL = 23;
- OP.SPKST = 24;
- OP.CWD = 25;
-
-
- /*
- * Parameters which may need to be changed for your machine:
- * MAXPACK, BRKCHR, MY...
- */
-
-
- STDIN = 0;
- STDOUT = 1;
-
- EOF = -1;
- ERR = -1;
-
- TRUE = 1;
- FALSE = 0;
-
- _SIZE = /4;
-
- MAX_BRKS = 10;
-
- DBG_OFF = 0;
- DBG_STATES = 1;
- DBG_PACKETS = 2;
- DBG_LOGFILE = 4;
- DBG_ALL = -1;
-
- FM_TEXT = 0;
- FM_ASA9 = 1;
- FM_BITS = 2;
-
- FL_SIZE = 5;
- FL_NAME = 0;
- FL_MODE = 1;
- FL_RAND = 2;
- FL_DISC = 3;
- FL_PERM = 4;
- FL_OVWR = 5;
-
- PAR_CMD = 0;
- PAR_FIL = 1;
- PAR_IDX = 2;
- PAR_RMT = 3;
-
-
- /*
- * Stuff what comes over comm-lines.
- */
-
- NULL = 0; /* ASCII NULL */
- SOH = 1; /* Start of header */
- LF = 10; /* ASCII Line Feed */
- CR = 13; /* ASCII Carriage Return */
- DC1 = 17; /* ASCII DC1 (XON) */
- DC3 = 19; /* ASCII DC3 (XOFF) */
- DEL = 127; /* Delete (rubout) */
-
-
- /*
- * Offsets in the Send-init packet.
- */
-
- SI_MAXPACK = 0;
- SI_MYTIME = 1;
- SI_MYPAD = 2;
- SI_MYPCHAR = 3;
- SI_MYEOL = 4;
- SI_MYQUOTE = 5;
- SI_MYBQUOTE = 6;
- SI_MYCHECK = 7;
- SI_MYREPTC = 8;
- SI_MYCAPS = 9;
- SI_MYSIZE = 10;
-
-
- /*
- * This kermit's init parameters
- */
-
- MAXPACK = 94; /* Maximum incoming packet size (max 94) */
- MYTIME = 10; /* Seconds after which I should be timed out */
- MYPAD = 0; /* Number of padding characters I will need (max 94) */
- MYPCHAR = DEL; /* Padding character I need */
- MYEOL = DC3; /* End-Of-Line character I need */
- MYQUOTE = '#'; /* Quote character I will use */
- MYBQUOTE = '&'; /* Eighth-bit quote char: ' ' => none */
- MYREPTC = '~'; /* Repeat prefix: ' ' => none */
- MYCHECK = '1'; /* Checksum type: '1' => default */
- MYCAPS = (CAP_TIMO|CAP_SERV); /* capability mask */
- CAP_TIMO = 0; /* I can do timeouts: 0 => no, 040 => yes */
- CAP_SERV = 020; /* I have server mode: 0 => no, 020 => yes */
- INIT_SIZ = 10; /* number of parameters we will look at in an init pak */
-
- MAXTIM = 30; /* Maximum timeout interval */
- MINTIM = 2; /* Minumum timeout interval */
- MAXTRY = 5; /* Times to retry a packet */
- ESCCHR = '^'; /* connect mode escape char */
-
- MAXLINE = 256; /* Size of packet buffers */
- MAXNAM = 12; /* Maximum name file name length */
- /* kermit/s/manif >> End << */
- /* kermit/s/extrn >> Begin << */
- /*
- * EXTRN -- EXTeRNal variables for Kermit.
- */
-
-
- /*
- * Commands enabled?
- */
-
- wat_lc { FALSE }; /* Have Waterloo style LC command? */
- wat_smcl { FALSE }; /* Have Waterloo style SMCL command? */
- wat_cwd { FALSE }; /* Have Working Directories enabled? */
-
-
- /*
- * .Bset Options.
- */
-
- .keep { 1 };
- .process { 0 };
-
- .optab [] {
- "?", BLNK_KWD,
- "Done", COMM_KWD,
- "Exit", COMM_KWD,
- "Quit", COMM_KWD,
- "Help", COMM_KWD,
- "Receive", COMM_KWD,
- "SENd", COMM_KWD,
- "SERver", COMM_KWD,
- "SET", COMM_KWD,
- "STatus", COMM_KWD,
- "indeX", SVAL_KWD,
- "Format", SVAL_KWD,
- "Checksum", SVAL_KWD,
- "DeBug", SVAL_KWD,
- "Delay", NVAL_KWD,
- "Random", PLUS_KWD|DASH_KWD,
- "Discard", PLUS_KWD|DASH_KWD,
- "RetryPacket", PLUS_KWD|DASH_KWD,
- "Permanent", PLUS_KWD|DASH_KWD,
- "TapeMode", PLUS_KWD|DASH_KWD,
- "Xon", PLUS_KWD|DASH_KWD,
- "OverWrite", PLUS_KWD|DASH_KWD,
- "SendEndOfLine", NVAL_KWD,
- "SendStartofPacket", NVAL_KWD,
- "ChangeWorkingDirectory", SVAL_KWD,
- -1 };
-
-
- /*
- * Global characters
- */
-
- stpkt { SOH }; /* Start-of-packet character to send (char) */
- padchar { NULL }; /* Padding character to send (char) */
- eol { CR }; /* End-Of-Line character to send (char) */
- quotec { '#' }; /* Incoming quote char. for control chars (char) */
- bquote { MYBQUOTE }; /* Incoming quote character for 8th-bit (char) */
- reptc { MYREPTC }; /* Incoming repeat prefix character (char) */
-
- state; /* Present state of the automaton (char) */
- lastpk; /* Last received packet type (char) */
- recpkt [MAXLINE]; /* Receive packet buffer (char) */
- packet [MAXLINE]; /* Packet buffer (char) */
- filnam [MAXLINE _SIZE]; /* current file name (char) */
- msghdr { "Kermit-GCOS" }; /* Message header */
-
- wc [MAXLINE _SIZE]; /* Working Catalog (char) */
-
- /*
- * Global Variables
- */
-
- size; /* Size of present data (int) */
- n; /* Message number (int) */
- rpsiz; /* Maximum receive packet size (int) */
- spsiz { 80 }; /* Maximum send packet size (int) */
- pad { 0 }; /* How much padding to send (int) */
- timint { 10 }; /* Timeout for foreign host on sends (int) */
- numtry; /* Times this packet retried (int) */
- oldtry; /* Times previous packet retried (int) */
- fd { ERR }; /* file pointer of file to read/write (file) */
- fderr { ERR }; /* file to send debug output to */
- fdtap { ERR }; /* file to read tape mode input from */
- image { FALSE }; /* YES means 8-bit mode (int) */
- remspd; /* speed of this tty (int) */
- remote { FALSE }; /* YES means we're a remote host kermit (int) */
- debug { DBG_OFF }; /* Type of debugging done (int) */
- eoflg; /* EOF flag for Send Data state (int) */
- hlpflg; /* Flag for Help command (int) */
- rflg; /* Flag for receive mode (int) */
- sflg; /* Flag for send mode (int) */
- srvflg; /* Flag for server mode (int) */
- setflg; /* Flag for Set command (int) */
- stsflg; /* Flag for Status command (int) */
- dobquo { FALSE }; /* YES => do 8th bit quoting (int) */
- dorept { FALSE }; /* YES => do repeat prefixing (int) */
- xonwait { FALSE }; /* YES => wait for XON before each packet send (int) */
- imgflg { FALSE }; /* YES => image-mode command flag set (int) */
- tapflg { TRUE }; /* YES => use paper tape mode for input */
- binfil { FM_TEXT }; /* YES => do 8 bit i/o on this file (int) */
-
- chktype { 1 }; /* Checksum type */
- delay { 10 }; /* Delay time */
- randflg { 0 }; /* YES => make file random */
- discflg { 0 }; /* YES => Discard incomplete file */
- retryflg { 1 }; /* YES => Retry every packet */
- prmflg { 1 }; /* YES => Always use permanent file */
- ovrflg { 0 }; /* YES => Overwrite existing files */
-
- eolpend { FALSE }; /* TRUE => We have a pending eol */
-
- curflgs [] { /* Vector containing the current file mode settings. */
- 0, /* File name */
- FM_TEXT, /* FL_BINF */
- FALSE, /* FL_RAND */
- FALSE, /* FL_DISC */
- TRUE, /* FL_PERM */
- FALSE /* FL_OVWR */
- };
-
- crctab [] {
- 0000000,
- 0010201,
- 0020402,
- 0030603,
- 0041004,
- 0051205,
- 0061406,
- 0071607,
- 0102010,
- 0112211,
- 0122412,
- 0132613,
- 0143014,
- 0153215,
- 0163416,
- 0173617
- };
-
- crctb2 [] {
- 0000000,
- 0010611,
- 0021422,
- 0031233,
- 0043044,
- 0053655,
- 0062466,
- 0072277,
- 0106110,
- 0116701,
- 0127632,
- 0137323,
- 0145154,
- 0155745,
- 0164576,
- 0174367
- };
-
- fillst; /* List of files to send */
- filcnt; /* Number of files supplied */
-
- /*
- * io error statuses from putrec and write (DRL DIO)
- */
- io.err[] {
- 0,
- "Not in aft",
- "Device attention",
- "End of reel",
- "Physical end of file",
- "Bad instruction",
- "Status 06",
- "Status 07",
- "Channel busy",
- "Status 11",
- "Status 12",
- "Data alert",
- "Status 14",
- "Status 15",
- "Status 16",
- "Physical end of file"
- };
-
- /*
- * Variables to handle paper tape mode buffering.
- */
-
- tpbuf[64]; /* Buffer to hold tap* sectors */
- tpcnt { 0 }; /* Number of characters in tap* buffer */
- tpidx { 0 }; /* Index of next character in tap* buffer */
- tpsect { 0 }; /* Next sector of tap* to be read */
- tpeof { 1 }; /* Do we need another DRL T.TPIN? */
-
- /*
- * Variables to handle file buffering.
- */
-
- flbuf[320]; /* Buffer to hold the current record */
- flcnt { 0 }; /* Number of characters in the record */
- flidx { 0 }; /* Index of next character in the record */
- flseg { 0 }; /* Segment number of partitioned record */
- flsec { 0 }; /* Index of sector to read next */
- flcrcnt { 0 }; /* Count of pending carriage returns */
- flunbuf[10] { 0 }; /* Ungot character buffer */
- /* kermit/s/extrn >> End << */
- /* kermit/s/main >> Begin << */
- /*
- * MAIN -- MAINline for Kermit.
- *
- * This is the main body of Kermit which calls the other
- * functions and procedures.
- */
-
- main() {
- extrn msghdr, wc, curflgs, fillst, filcnt;
- auto retn, cmdstr[MAXLINE _SIZE];
-
- printf( "%s: Version 1.1*n*n", msghdr );
- flush();
-
- getwd( wc );
-
- nobrks( MAX_BRKS );
-
- reread();
- getstr( cmdstr );
- rep.st( cmdstr, 0, "", .span( cmdstr, .break( cmdstr, 0, " " ), " " ) );
-
- retn = getcmd( cmdstr, PAR_CMD, curflgs );
-
- if( retn == 'a' || !retn ) /* It aborted */
- exit( ERR ); /* End kermit with an error status */
- else if( retn == 'n' ) { /* No command given */
- repeat {
- nobrks( MAX_BRKS );
- prompt( "%s>", msghdr );
- getstr( cmdstr );
- if( char(cmdstr,0) == '!' ) {
- rep.st( cmdstr, 0, "", 1 );
- system( cmdstr );
- }
- else {
- retn = getcmd( cmdstr, PAR_CMD, curflgs );
- if( retn == 'd' )
- break;
- }
- }
- }
-
- } /* main */
- /* kermit/s/main >> End << */
- /* kermit/s/bufemp >> Begin << */
- /*
- * BUFEMP -- BUFfer EMPty.
- *
- * Get data from an incoming packet into a file
- * Control-quoting, 8-bit & repeat prefixes are done.
- * Note that parity stripping was already done in spack.
- *
- * Assumes putch works with 8-bit data.
- *
- * buffer -- the buffer
- * len -- length
- *
- * Returns 0 if successful, negative of the major
- * filesystem status if not.
- */
-
- bufemp( buffer, len ) {
- extrn quotec, bquote, reptc, dobquo, dorept;
- auto sts, nrep, i, j, c, c7, c8;
-
- for( i = 0; i < len; ++i ) { /* Loop through data */
- c = buffer[i]; /* Get character */
-
- if( !dorept || c != reptc ) /* Repeat prefix? */
- nrep = 1;
- else {
- nrep = unchar(buffer[++i]); /* Get the count */
- c = buffer[++i]; /* Next char */
- }
-
- if( !dobquo || c != bquote ) /* Eighth-bit quote? */
- c8 = 0;
- else {
- c8 = 128; /* save bit's value */
- c = buffer[++i]; /* Next char */
- }
-
- if( c == quotec ) { /* A quoted char */
- c = buffer[++i]; /* get the next char */
- if( (c7 = mask(c)) >= '?' && c7 <= '_' )
- c = ctl(c); /* Controlify the char */
- }
-
- c |= c8; /* Or in eighth bit */
-
- for( j = 1; j <= nrep; ++j ) /* Put out correct number of chars */
- if( (sts = putch( c )) < 0 )
- return( sts );
- }
-
- return( 0 );
- } /* bufemp */
- /* kermit/s/bufemp >> End << */
- /* kermit/s/bufill >> Begin << */
- /*
- * BUFILL -- BUFfer FILL.
- *
- * Get a bufferful of data from the file that's being sent.
- * Control-quoting, 8-bit & repeat prefixes are done.
- *
- * Assumes that getch returns 8-bit data.
- */
-
- bufill( buffer ) {
- extrn spsiz, dobquo, dorept;
- auto c, c1, c7, i, j;
-
- /*
- * Loop on characters until end of file
- * or the packet is full.
- */
-
- i = 0;
- while( i + 1 < spsiz - 9 && (c = getch()) != EOF ) {
- /*
- * Repeat prefixing enabled,
- * cannot do repeat counts for CR-LFs.
- */
- if( dorept && c != '*r' && c != '*n' ) {
- for( j = 1; (c1 = getch()) == c; ++j ) /* look for repeated chars */
- if( j >= 94 ) /* 94 char repeat limit */
- break;
- ungtch(c1); /* put back the one that didn't match */
- if( j < 3 ) { /* If less than threshold for doing repeat */
- for( ; j > 1; --j ) /* put them back */
- ungtch(c);
- }
- else {
- buffer[i++] = MYREPTC; /* repeat prefix */
- buffer[i++] = tochar(j); /* repeat count */
- }
- }
-
- if( c > 127 && dobquo ) { /* If eighth bit on */
- buffer[i++] = MYBQUOTE; /* add eighth-bit quote */
- c = mask(c); /* strip down to seven bits */
- }
-
- /*
- * Do we need to quote this char?
- */
-
- c7 = mask(c); /* A seven bit version of c */
- if( c7 < ' ' || c7 == DEL || c7 == MYQUOTE
- || (c7 == MYBQUOTE && dobquo) || (c7 == MYREPTC && dorept) ) {
- buffer[i++] = MYQUOTE; /* add quote char */
- if( c7 < ' ' || c7 == DEL )
- c = ctl(c); /* de-controlify control char */
- }
-
- buffer[i++] = c; /* Use the eight bit version */
-
- } /* while */
-
- buffer[i] = '*0';
-
- return( i );
- } /* bufill */
- /* kermit/s/bufill >> End << */
- /* kermit/s/chksum >> Begin << */
- /*
- * CHKSUM -- compute the CHecKSUM.
- * Add the upper two bits into the lower six.
- * The Kermit Protocol Manual details how the checksum is formed.
- */
-
- chksum( sum, len, num, type, data ) {
- extrn chktype, crctab, crctb2;
- auto i, ch;
-
- if( chktype == 1 || type == 'S' || type == 'I' || type == 'R' )
- return( (((sum&0300) >> 6) + sum) & 077 );
- else if( chktype == 2 )
- return( sum & 07777 );
- else if( chktype == 3 ) {
- ch = tochar(len+3);
- sum = crctab[(ch>>4)&017] ^ crctb2[ch&017];
- ch = tochar(num) ^ (sum & 0377);
- sum = (sum>>8) ^ crctab[(ch>>4)&017] ^ crctb2[ch&017];
- ch = type ^ (sum & 0377);
- sum = (sum>>8) ^ crctab[(ch>>4)&017] ^ crctb2[ch&017];
- for( i = 0; (ch = data[i]) != '*0'; ++i ) {
- ch ^= (sum & 0377);
- sum = (sum>>8) ^ crctab[(ch>>4)&017] ^ crctb2[ch&017];
- }
- }
-
- return( sum );
- } /* chksum */
- /* kermit/s/chksum >> End << */
- /* kermit/s/ctl >> Begin << */
- /*
- * CTL -- ConTroLlify a character.
- *
- * Turns a control character into a printable charcter and vice versa
- * by toggling the control bit (ie. ^A becomes A and A becomes ^A).
- */
-
- ctl( ch ) {
- auto mask;
-
- return( ch ^ 64 ); /* toggle the control bit */
-
- } /* ctl */
- /* kermit/s/ctl >> End << */
- /* kermit/s/eprintf >> Begin << */
- /*
- * EPRINTF -- Error PRINTF.
- * If the appropriate debug states are set,
- * do a printf to the Error output.
- */
-
- eprintf( type, format, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) {
- extrn fderr, debug;
-
- if( debug & type ) {
- if( fderr == ERR )
- fderr = open( "kerm**dbg", "wu" );
- printf( fderr, "%r", &format );
- }
-
- } /* eprintf */
- /* kermit/s/eprintf >> End << */
- /* kermit/s/errmsg >> Begin << */
- /*
- * ERRMSG -- send an ERRor MeSsaGe.
- *
- * Print error message, or send it.
- */
-
- errmsg( format, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) {
- extrn n, remote, packet, msghdr;
- auto len, str[MAXLINE _SIZE];
-
- print( str, "%s: %r", msghdr, &format );
-
- eprintf( DBG_ALL, "%s*n", str );
-
- if( !remote )
- printf( -4, "%s*n", str );
- else {
- lchar( str, MAXPACK, '*0' ); /* Truncate to legal size */
- len = str2pkt( packet, str );
- spack( 'E', n, len, packet ); /* Send the error packet */
- flusheol();
- }
-
- } /* errmsg */
- /* kermit/s/errmsg >> End << */
- /* kermit/s/errpkt >> Begin << */
- /*
- * ERRPKT -- print an ERRor PacKeT.
- */
-
- errpkt( pkt ) {
- auto str[MAXLINE _SIZE];
-
- pkt2str( str, pkt );
- eprintf( DBG_ALL, "Error from remote Kermit: %s*n", str );
-
- } /* errpkt */
- /* kermit/s/errpkt >> End << */
- /* kermit/s/failmsg >> Begin << */
- /*
- * FAILMSG -- send a FAILure MeSsaGe.
- *
- * Send message about a protocol failure.
- */
-
- failmsg( oldstate ) {
- extrn fd, remote, state, lastpk, filnam;
- auto i, line[MAXLINE _SIZE];
-
- i = 1;
- switch( state ) { /* Find the appropriate error message */
- case 'a': /* a message was already received or sent */
- return;
- case 'm':
- concat( line, "Retry limit exceeded" );
- break;
- case 'n':
- concat( line, "Wrong packet number received" );
- break;
- case 'w':
- print( line, "Wrong packet type %c received", lastpk );
- break;
- default:
- concat( line, "Illegal internal state" );
- }
-
- concat( line, line, " while in state " );
- addchar( line, oldstate ); /* Give the state */
- if( fd != ERR) { /* Give the file, if open */
- concat( line, line, ", in file ", filnam );
- }
-
- concat( line, line, " " );
- errmsg( line ); /* Send error message to appropriate place */
- if( remote )
- eprintf( DBG_ALL, line ); /* Send a copy to ERROUT */
-
- } /* failmsg */
- /* kermit/s/failmsg >> End << */
- /* kermit/s/fclose >> Begin << */
- /*
- * FCLOSE -- File CLOSE routine.
- * Returns 0 if successful, the negative of the major
- * filesystem status if not.
- */
-
- fclose( fd, errflg ) {
- extrn discflg, randflg, filnam, flbuf;
- auto fd2, nsec, sts;
-
- if( !discflg ) {
- close( fd );
- return( 0 );
- }
-
- if( !errflg ) {
- close( fd );
- fd = open( "kerm**tmp", randflg ? "rufeb" : "rufe" );
- fd2 = open( filnam, randflg ? "wufeb" : "wufe" );
- if( fd2 < 0 )
- return( fd2 );
- for( nsec = 0; read( fd, flbuf, nsec, 320 ) > 0; ++nsec )
- if( (sts = write( fd2, flbuf, nsec, 320 )) < 0 )
- return( sts );
- close( fd2 );
- }
-
- close( fd );
- retfil( "kerm**tmp" );
-
- return( 0 );
- } /* fclose */
- /* kermit/s/fclose >> End << */
- /* kermit/s/flusheol >> Begin << */
- /*
- * FLUSHEOL -- FLUSH the End Of Line if necessary.
- */
-
- flusheol() {
- extrn eolpend, eol;
-
- if( eolpend ) {
- putchar( eol );
- flush();
- }
-
- } /* flusheol */
- /* kermit/s/flusheol >> End << */
- /* kermit/s/generic >> Begin << */
- /*
- * GENERIC -- execute a GENERIC command.
- */
-
- generic( num, cmd, packet, flags ) {
- extrn msghdr, wc, flsyerr, wat_lc, wat_smcl;
- auto len, str, str2, unit, buf, temp, arglst[1], sts[1];
-
- str = allocate( MAXLINE _SIZE );
-
- switch( cmd ) { /* What is the command ? */
-
- case 'F': /* Finish, shut down Kermit */
- print( str, "%s: terminated.", msghdr );
- len = str2pkt( packet, str );
- spack( 'Y', num, len, packet ); /* Acknowledge receipt of command */
- return( FALSE ); /* Exit Server Mode */
- break;
-
- case 'L': /* Shut down Kermit and logout. */
- spack( 'Y', num, 0, 0 ); /* Acknowledge receipt of command */
- flusheol();
- quit(); /* Execute session logout */
- break;
-
- case 'C': /* Change Working Directory */
- pkt2str( str, packet );
- lchar( str, unchar(char(str,0)) + 1, '*0' );
- rep.st( str, 0, "", 1 );
- /*
- * There should be a validity check here.
- */
- if( !nullstr(str) ) {
- if( char(str,0) == '/' )
- concat( wc, wc, str );
- else
- concat( wc, str );
- }
- print( str, "%s: Working Directory = %s", msghdr, wc );
- len = str2pkt( packet, str );
- spack( 'Y', num, len, packet );
- break;
-
- case 'D': /* Directory */
- if( !wat_lc ) {
- errmsg( "Remote Directory command is not available." );
- break;
- }
- pkt2str( str, packet );
- rep.st( str, 0, "", 1 );
- if( packet[0] == 0 )
- concat( str, wc );
- if( char(str,0) == '/' )
- rep.st( str, 0, wc, 0 );
- system( "lc %s >kerm**tmp", str );
- mesgsw( "kerm**tmp", " " );
- break;
-
- case 'E': /* Erase (release) a file */
- pkt2str( str, packet );
- rep.st( str, 0, "", 1 );
- wdfile( str, flags[FL_PERM] );
- buf = allocate( 43 );
- if( scaf( str, buf, 0, 43 ) < 0 )
- errmsg( "%s: Bad pathname", str );
- else {
- temp = allocate( 380 );
- arglst[0] = sts << 18;
- arglst[1] = buf << 18;
- drl.drl( T.FLAC_, arglst, 22<<18 | temp );
- sts[0] = ( sts[0] >> 24 ) & 03777;
- if( sts[0] != 0 )
- errmsg( "%s: %s", str, flsyerr[sts[0]] );
- else {
- print( temp, "%s: File %s released.", msghdr, str );
- len = str2pkt( packet, temp );
- spack( 'Y', num, len, packet );
- }
- }
- break;
-
- case 'H': /* print Help information */
- pkt2str( str, packet );
- rep.st( str, 0, "", 1 );
- if( packet[0] == 0 || nullstr(str) )
- concat( str, "HELP" );
- unit = open( "kerm**tmp", "wu" );
- prhelp( str, unit );
- close( unit );
- mesgsw( "kerm**tmp", " " );
- break;
-
- case 'T': /* Type (list) a file */
- pkt2str( str, packet );
- rep.st( str, 0, "", 1 );
- wdfile( str, flags[FL_PERM] );
- mesgsw( str, str );
- break;
-
- case 'U': /* Disk Usage Query */
- if( !wat_smcl ) {
- errmsg( "Remote Space command is not available." );
- break;
- }
- system( "smcl >kerm**tmp" );
- mesgsw( "kerm**tmp", " " );
- break;
-
- case 'Q': /* Server status Query */
- unit = open( "kerm**tmp", "wu" );
- printf( unit, "%s: Server Mode.*n", msghdr );
- prsts( unit );
- close( unit );
- mesgsw( "kerm**tmp", " " );
- break;
-
- case 'J': /* produce a Journal */
- errmsg( "%s: Transaction logging is not yet implemented.", msghdr );
- break;
-
- default: /* Anything else */
- errmsg( "%c: generic command not implemented.", cmd );
- } /* switch */
-
- return( TRUE );
- } /* generic */
- /* kermit/s/generic >> End << */
- /* kermit/s/get_rec >> Begin << */
- /*
- * GET_REC -- GET a RECord from a file.
- */
-
- get_rec() {
- extrn fd, binfil, flbuf, flidx, flcnt, flsec;
- auto sts;
-
- if( binfil != FM_TEXT ) {
- sts = read( fd, flbuf, flsec, 320 );
- flsec += 5;
- if( sts < 0 ) {
- sts = - sts;
- if( sts != 017 )
- eprintf( DBG_ALL, "On Read: status = %2o*n", sts );
- return( FALSE );
- }
-
- if( binfil == FM_ASA9 )
- flcnt = (320*4);
- else
- flcnt = ((320/2)*9);
- flidx = 0;
- }
- else {
- sts = getrcp( fd );
- if( sts < 0 ) {
- return( FALSE );
- }
- copy( flbuf, sts, sts[0]>>18 );
- flidx = 0;
- if( flbuf[0] == 01200600 && flbuf[1] == '*x*x*x*x' )
- flbuf[0] = 0600;
- flcnt = flbuf[0]>>16;
- if( flcnt & 03 )
- flcnt -= 4;
- sts = (flbuf[0]>>10) & 03;
- if( sts == 0 || sts == 3 ) {
- lchar( &flbuf[1], flcnt++, '*r' );
- lchar( &flbuf[1], flcnt++, '*n' );
- }
- }
-
- return( TRUE );
- } /* get_rec */
- /* kermit/s/get_rec >> End << */
- /* kermit/s/getch >> Begin << */
- /*
- * GETCH -- GET a CHaracter from a file.
- */
-
- getch() {
- extrn flunbuf, flbuf, flidx, flcnt, binfil;
- auto ch;
-
- /*
- * If a character has been put back,
- * return it first.
- */
-
- if( flunbuf[0] > 0 )
- return( flunbuf[ flunbuf[0]-- ] );
-
- /*
- * Get a REAL character.
- */
-
- if( /*flbuf[0] == 0170000 ||*/ (flidx >= flcnt && !get_rec()) )
- return( EOF );
-
- if( binfil == FM_TEXT )
- return( char( &flbuf[1], flidx++ ) );
- else if( binfil == FM_ASA9 )
- return( char( flbuf, flidx++ ) );
-
- switch( flidx % 9 ) {
- case 0: ch = flbuf[2*(flidx/9)]>>28; break;
- case 1: ch = flbuf[2*(flidx/9)]>>20; break;
- case 2: ch = flbuf[2*(flidx/9)]>>12; break;
- case 3: ch = flbuf[2*(flidx/9)]>>4; break;
- case 4: ch = flbuf[2*(flidx/9)]<<4
- | flbuf[2*(flidx/9)+1]>>32; break;
- case 5: ch = flbuf[2*(flidx/9)+1]>>24; break;
- case 6: ch = flbuf[2*(flidx/9)+1]>>16; break;
- case 7: ch = flbuf[2*(flidx/9)+1]>>8; break;
- case 8: ch = flbuf[2*(flidx/9)+1]; break;
- } /* switch */
-
- ++flidx;
- return( ch & 0377 );
- } /* getch */
- /* kermit/s/getch >> End << */
- /* kermit/s/getcmd >> Begin << */
- /*
- * GETCMD -- GET and parse a CoMmanD.
- * Parse a command line and set options.
- * Execute the command if desired.
- */
-
- getcmd( cmdstr, cmdflg, in_flags ) {
- extrn fillst, filcnt, filnam, wc, .argtype;
- extrn rflg, sflg, srvflg;
- extrn fderr, fdtap, debug;
- extrn chktype, delay, retryflg, xonwait, tapflg, eol, stpkt, remote;
- auto argc, argv, buf, cmd, i, info, p, ix, tmp, retn, flags[FL_SIZE];
- auto nerrors, old_remote, randseen, formseen;
-
- buf = allocate( 100 );
- argv = .bset( cmdstr, buf );
- argc = argv >> 18;
- argv &= 0777777;
-
- copy( flags, in_flags, FL_SIZE );
- flags[FL_NAME] = 0;
-
- nerrors = 0;
- randseen = formseen = FALSE;
-
- /*
- * Find the command (if any)
- */
-
- if( argc < 1 || (cmd = argv[0]>>18) < OP.DONE || cmd > OP.STAT )
- cmd = OP.SET;
-
- if( cmdflg == PAR_RMT
- && !(cmd == OP.HELP || cmd == OP.SET || cmd == OP.STAT) )
- return( 'n' );
-
- for( i = 0; i < argc; ++i )
- switch( (info = argv[i]) >> 18 ) {
-
- case OP.FILE:
- if( cmdflg == PAR_CMD && cmd == OP.HELP ) {
- prhelp( info );
- return( TRUE );
- }
- else if( cmdflg == PAR_CMD && i == 0 ) {
- errmsg( "%s: Unknown command.", info );
- return( 'n' );
- }
- else if( cmdflg == PAR_CMD && cmd != OP.SEND ) {
- errmsg( "%s: Filenames can only be used with SEND", info );
- ++nerrors;
- }
- break;
-
- case OP.INDEX:
- if( cmdflg == PAR_CMD && cmd != OP.SEND ) {
- errmsg( "indeX=%s: Can only be used with SEND", info );
- ++nerrors;
- }
- break;
-
- case OP.QUERY:
- if( cmdflg == PAR_CMD && cmd == OP.HELP )
- prhelp( "?" );
- else
- prquery( cmd, i );
-
- return( TRUE );
-
- case OP.DONE::OP.STAT:
- break;
-
- case OP.FORMAT:
- formseen = TRUE;
- if( .abbrv( "Text", info ) != -1 )
- flags[FL_MODE] = FM_TEXT;
- else if( .abbrv( "BYtestream", info ) != -1 )
- flags[FL_MODE] = FM_ASA9;
- else if( .abbrv( "BItstream", info ) != -1 )
- flags[FL_MODE] = FM_BITS;
- else {
- errmsg( "Bad file format: Format=%s", info );
- ++nerrors;
- }
- break;
-
- case OP.CHKSUM:
- errmsg( "Checksum=%s: Option is not yet implemented.", info );
- ++nerrors;
- break;
- if( cmdflg != PAR_CMD ) {
- errmsg( "Checksum=%s: Can only be used on command lines.", info );
- ++nerrors;
- }
- else {
- if( .abbrv( "Single", info ) != -1 || equal( "1", info ) )
- chktype = 1;
- else if( .abbrv( "Double", info ) != -1 || equal( "2", info ) )
- chktype = 2;
- else if( .abbrv( "CyclicRedundancyCheck", info ) != -1
- || equal( "3", info ) )
- chktype = 3;
- else {
- errmsg( "Checksum=%s: Bad Checksum type.", info );
- ++nerrors;
- }
- }
- break;
-
- case OP.DEBUG:
- if( cmdflg != PAR_CMD && cmdflg != PAR_RMT ) {
- errmsg( "DeBug=%s: Can only be used on command lines.", info );
- ++nerrors;
- }
- else {
- if( .abbrv( "Off", info ) != -1 )
- debug = DBG_OFF;
- else if( .abbrv( "States", info ) != -1 )
- debug |= DBG_STATES;
- else if( .abbrv( "Packets", info ) != -1 )
- debug |= DBG_PACKETS;
- else if( .abbrv( "Logfile", info ) != -1 )
- debug |= DBG_LOGFILE;
- else if( .abbrv( "All", info ) != -1 )
- debug |= DBG_ALL;
- else {
- errmsg( "DeBug=%s: Invalid debug setting.", info );
- ++nerrors;
- }
- }
- break;
-
- case OP.DELAY:
- if( cmdflg != PAR_CMD && cmdflg != PAR_RMT ) {
- errmsg( "Delay=%d: Can only be used on command lines.", *info );
- ++nerrors;
- }
- else {
- if( *info < 0 ) {
- errmsg( "Delay=%d: Delay must be positive", *info );
- ++nerrors;
- }
- else
- delay = *info;
- }
- break;
-
- case OP.SEOL:
- if( cmdflg != PAR_CMD && cmdflg != PAR_RMT ) {
- errmsg( "SendEndOfLine=%d: Can only be used on command lines.", *info );
- ++nerrors;
- }
- else {
- if( *info < 0 || *info > 127 ) {
- errmsg( "SendEndOfLine=%d: Must be within 0..127.", *info );
- ++nerrors;
- }
- else
- eol = *info;
- }
- break;
-
- case OP.SPKST:
- if( cmdflg != PAR_CMD && cmdflg != PAR_RMT ) {
- errmsg(
- "SendStartofPacket=%d: Can only be used on command lines.",
- *info );
- ++nerrors;
- }
- else {
- if( *info < 0 || *info > 127 ) {
- errmsg( "SendStartofPacket=%d: Must be within 0..127.",
- *info );
- ++nerrors;
- }
- else
- stpkt = *info;
- }
- break;
-
- case OP.CWD:
- /*
- * There should be a validity check here.
- */
- if( !nullstr(info) && !equal(info,"?") ) {
- if( char(info,0) == '/' )
- concat( wc, wc, info );
- else
- concat( wc, info );
- }
- errmsg( "Working Directory = %s", wc );
- break;
-
- case OP.RANDOM:
- randseen = TRUE;
- flags[FL_RAND] = ( .argtype[i] == '+' );
- break;
-
- case OP.DISCARD:
- flags[FL_DISC] = ( .argtype[i] == '+' );
- break;
-
- case OP.RETRY:
- errmsg( "%cRetryPacket: Option is not yet implemented.", .argtype[i] );
- ++nerrors;
- break;
- if( cmdflg != PAR_CMD && cmdflg != PAR_RMT ) {
- errmsg( "%cRetryPacket: Must be used with SET.", .argtype[i] );
- ++nerrors;
- }
- else {
- retryflg = ( .argtype[i] == '+' );
- }
- break;
-
- case OP.PERM:
- flags[FL_PERM] = ( .argtype[i] == '+' );
- break;
-
- case OP.TAPMOD:
- if( cmdflg != PAR_CMD && cmdflg != PAR_RMT ) {
- errmsg( "%cTapeMode: Must be used with SET.", .argtype[i] );
- ++nerrors;
- }
- else {
- tapflg = ( .argtype[i] == '+' );
- }
- break;
-
- case OP.XON:
- errmsg( "%cXon: Option is not yet implemented.", .argtype[i] );
- ++nerrors;
- break;
- if( cmdflg != PAR_CMD && cmdflg != PAR_RMT ) {
- errmsg( "%cXonwait: Must be used with SET.", .argtype[i] );
- ++nerrors;
- }
- else {
- xonwait = ( .argtype[i] == '+' );
- }
- break;
-
- case OP.OVWRITE:
- flags[FL_OVWR] = ( .argtype[i] == '+' );
- break;
-
- default:
- errmsg( "%s: Unknown option.", info );
- ++nerrors;
- } /* switch */
-
- if( nerrors )
- return( 'n' );
-
- if( cmdflg != PAR_IDX ) {
- fillst = getvec( 0 );
- fillst[0] = 0;
- filcnt = 0;
- }
-
- if( !randseen && formseen )
- flags[FL_RAND] = ( flags[FL_MODE] != FM_TEXT );
-
- for( i = 0; i < argc; ++i )
- switch( (info = argv[i]) >> 18 ) {
-
- case OP.FILE:
- tmp = allocate( MAXLINE _SIZE );
- concat( tmp, info );
- wdfile( tmp, flags[FL_PERM] );
-
- p = getvec( FL_SIZE );
- copy( p, flags, FL_SIZE );
- p[FL_NAME] = concat( getvec(length(tmp)/4), tmp );
-
- fillst = addvec( fillst, 1 );
- fillst[++fillst[0]] = p;
- break;
-
- case OP.INDEX:
- ix = open( info, "rudfem" );
- if( ix > 0 ) {
- tmp = allocate( MAXLINE _SIZE );
- while( getstr( ix, tmp ) ) {
- getcmd( tmp, PAR_IDX, flags );
- }
- close( ix );
- }
- break;
- } /* switch */
-
- if( debug && fderr == ERR )
- fderr = open( "kerm**dbg", "wu" );
-
- if( tapflg && fdtap == ERR )
- fdtap = open( "tap**", "rwbut" );
-
- if( cmdflg == PAR_CMD ) {
- switch( cmd ) {
- case OP.DONE:
- case OP.EXIT:
- case OP.QUIT:
- retn = 'd';
- break;
- case OP.HELP:
- prhelp( "HELP" );
- flush();
- retn = TRUE;
- break;
- case OP.RECV:
- rflg = 1;
- printf( "Escape back to your local KERMIT and enter a SEND command.*n" );
- flush();
- old_remote = remote;
- remote = TRUE;
- retn = recsw( flags ); /* Go to receive state */
- remote = old_remote;
- rflg = 0;
- break;
- case OP.SEND:
- if( fillst[0] == 0 ) /* If no file names given */
- printf( "No file names supplied.*n" );
- else {
- sflg = 1;
- printf( "Escape back to your local KERMIT and enter RECEIVE mode.*n" );
- flush();
- old_remote = remote;
- remote = TRUE;
- retn = sendsw('S'); /* Go to send state */
- remote = old_remote;
- sflg = 0;
- }
- break;
- case OP.SERV:
- printf( "*nEntering Server Mode.*n" );
- printf( "Escape back to your local KERMIT " );
- printf( "and use server commands.*n" );
- printf( "To exit Server Mode, enter the FINISH " );
- printf( "command from your local KERMIT.*n" );
- printf( "To exit KERMIT in an emergency, " );
- printf( "enter control-D control-S (^D^S)*n" );
- flush();
-
- srvflg = 1;
- old_remote = remote;
- remote = TRUE;
- retn = server( flags ); /* Invoke server */
- remote = old_remote;
- srvflg = 0;
- printf( "*nExiting Server Mode.*n" );
- flush();
- break;
- case OP.SET:
- retn = 'n';
- break;
- case OP.STAT:
- prsts();
- flush();
- break;
- default:
- retn = 'n'; /* No command given */
- } /* switch */
- }
-
- if( cmdflg == PAR_CMD && retn == 'n' )
- copy( in_flags, flags, FL_SIZE );
-
- return( retn );
- } /* getcmd */
- /* kermit/s/getcmd >> End << */
- /* kermit/s/getcomm >> Begin << */
- /*
- * GETCOMM -- GET a char from the COMMunications line.
- * If not in paper tape mode, just do a getchar.
- * If in paper tape mode, read the tap* buffer.
- */
-
- getcomm() {
- extrn tapflg, fdtap, tpbuf, tpcnt, tpidx, msghdr;
- auto ch;
-
- if( !tapflg ) {
- ch = getchar();
- eprintf( DBG_PACKETS, "%c", ch );
- if( nobrks() ) {
- printf( -4, "%s: Break key.*n", msghdr );
- printf( -4, "To exit KERMIT type control-D (^D)" );
- flush();
- nobrks( MAX_BRKS );
- }
- return( ch );
- }
-
- if( tpidx >= tpcnt ) /* No characters left */
- rdcomm();
-
- ch = char( &tpbuf[2], tpidx++ );
- eprintf( DBG_PACKETS, "%c", ch );
-
- return( ch );
- } /* getcomm */
- /* kermit/s/getcomm >> End << */
- /* kermit/s/getfil >> Begin << */
- /*
- * GETFIL -- GET a FILe.
- * Open a new file, overwriting any existing file.
- * Returns 0 if successful, 'a' if no clash resolution possible,
- * and the negative of the filact error status if the file could
- * not be created or accessed.
- */
-
- getfil() {
- extrn fd, imgflg, filnam, fillst, filcnt, wc;
- extrn binfil, randflg, discflg, prmflg, ovrflg;
- extrn flbuf, flidx, flcnt, flseg, flcrcnt, flsec;
-
- concat( filnam, fillst[1][FL_NAME] );
- binfil = fillst[1][FL_MODE];
- randflg = fillst[1][FL_RAND];
- discflg = fillst[1][FL_DISC];
- prmflg = fillst[1][FL_PERM];
- ovrflg = fillst[1][FL_OVWR];
- eprintf( DBG_ALL, "Random=%d, Format=%d", randflg, binfil );
-
- /*
- * Make sure filnam is properly constructed
- */
-
- innam( filnam, prmflg );
-
- if( !ovrflg )
- if( !rsclash( filnam ) )
- return( - 011 ); /* Non-unique name */
-
- if( discflg )
- retfil( "kerm**tmp" );
- fd = open( discflg ? "kerm**tmp" : filnam, randflg ? "wufeb" : "wufe" );
- eprintf( DBG_ALL, "Attempt to open file: '%s'*n", filnam );
-
- if( fd < 0 )
- return( fd ); /* Return FILACT status */
-
- /*
- * Initialize the file buffer.
- */
-
- if( binfil == FM_TEXT )
- flcnt = 318*4;
- else if( binfil == FM_ASA9 )
- flcnt = 320*4;
- else
- flcnt = ((320/2)*9);
-
- flidx = 0;
- flsec = 0;
- flseg = 0;
- flcrcnt = 0;
- zero( flbuf, 320 );
-
- return( 0 ); /* Return file descriptor */
- } /* getfil */
- /* kermit/s/getfil >> End << */
- /* kermit/s/getwd >> Begin << */
- /*
- * GETWD -- GET the initial Working Directory.
- * If not on GCOS8, this is the logon userid.
- */
-
- %b/manif/ust
-
- getwd( wc ) {
- extrn wat_cwd;
- auto size, vec;
- auto catf[.LCWD_*4 + 1];
-
- if( !wat_cwd || !.gcos8() ) {
- getumc( wc );
- return( wc );
- }
-
- ++catf; /* step over the size word */
- p.ust( &catf[-1], .LCWD_*4+1, .LDUWD_ );
- size = (catf[-1] >> 16) + 1;
- size[vec = .vectr(size, size)] = -1;
- ++vec;
- .copy( vec, catf, size-2 );
- .unscaf( wc, vec, 1 );
- rlsevec( vec-1, vec[-1] );
-
- return( wc );
- } /* getwd */
- /* kermit/s/getwd >> End << */
- /* kermit/s/gnxtfl >> Begin << */
- /*
- * GNXTFL -- Get NeXT FiLe.
- *
- * Get next file from command line.
- */
-
- gnxtfl() {
- extrn fd, imgflg, binfil, filnam, msghdr, fillst, filcnt, wc;
- extrn randflg;
- extrn flidx, flcnt, flsec, flseg, flcrcnt, flunbuf, flbuf;
- auto tmp;
-
- if( filcnt >= fillst[0] ) /* Otherwise, get next file name */
- return( 'B' ); /* No more names - break transmission */
-
- concat( filnam, fillst[++filcnt][FL_NAME] );
- binfil = fillst[filcnt][FL_MODE];
- randflg = fillst[filcnt][FL_RAND];
-
- tmp = fillst[filcnt][FL_NAME];
- rlsevec( tmp, length(tmp)/4 );
- rlsevec( fillst[filcnt], FL_SIZE );
-
- /*
- * Make sure filnam is properly constructed
- */
-
- innam( filnam, fillst[filcnt][FL_PERM] );
- fd = open( filnam, randflg ? "rufeb" : "rufe" );
- if( fd < 0 ) { /* If it doesn't exist */
- errmsg( "Can't open file %s", filnam ); /* Send error message */
- return( 'a' ); /* Abort */
- }
-
- eprintf( DBG_ALL, "%s: sending file '%s'", msghdr, filnam );
-
- outnam( filnam ); /* Put name into standard format */
-
- eprintf( DBG_ALL, " as '%s'*n", filnam );
-
- flidx = 0;
- flcnt = 0;
- flsec = 0;
- flseg = 0;
- flcrcnt = 0;
- flunbuf[0] = 0;
- flbuf[0] = 0;
-
- return( 'F' ); /* Ready to send new file. */
- } /* gnxtfl */
- /* kermit/s/gnxtfl >> End << */
- /* kermit/s/innam >> Begin << */
- /*
- * INNAM -- INput NAMe.
- *
- * Change file name to a local compatible name.
- *
- * *** MACHINE DEPENDENT SUBROUTINE ***
- * Makes sure that an incoming file has a name that the local system
- * recognizes as valid.
- */
-
- innam( name, prmflg ) {
- auto i, j, ch;
-
- /*
- * Make sure that name
- * contains only valid chars.
- */
-
- trim( lowercase(name) );
-
- if( !prmflg && .break( name, 0, "/$" ) == length(name) ) {
- if( length(name) > 8 )
- lchar( name, 8, '*0' );
- return;
- }
-
- for( i = j = 0; (ch = char(name,i)) != '*0'; ++i )
- if( any( ch, "abcdefghijklmnopqrstuvwxyz0123456789_.-/$*"**" ) != -1 )
- lchar( name, j++, ch );
- lchar( name, j, '*0' );
-
- /*
- * Make sure name is
- * properly constructed.
- */
-
- i = 0;
- if( char(name,0) == '/' )
- i = 1;
-
- for( ; i == 0 || char(name,i-1) == '/'; i = j + 1 ) {
- j = .break( name, i, "/$*"" );
- if( j - i > 12 ) {
- rep.st( name, i+12, "", j-i-12 );
- j = i + 12;
- }
- if( (ch = char(name,j)) == '$' ) {
- j = .break( name, i = j + 1, "/$*"" );
- if( j - i > 12 ) {
- rep.st( name, i+12, "", j-i-12 );
- j = i + 12;
- }
- }
- } /* for */
-
- } /* innam */
- /* kermit/s/innam >> End << */
- /* kermit/s/mask >> Begin << */
- /*
- * MASK -- MASK off the parity bit.
- * Returns the lower seven bits.
- */
-
- mask( c ) {
-
- return( c & 127 );
- } /* mask */
- /* kermit/s/mask >> End << */
- /* kermit/s/mesgsw >> Begin << */
- /*
- * MESGSW -- MESseGe SWitcher.
- *
- * Mesgsw is the state table switcher for sending
- * long replies to queries or commands. It loops
- * until either it finishes, or an error is found.
- * The routines called by mesgsw are responsible
- * for changing the state.
- *
- * fname -- name of file to be sent.
- * sname -- name to send.
- */
-
- mesgsw( fname, sname ) {
- extrn n, numtry, fd, state, fillst, filcnt;
- auto lstate, llstate;
-
- fillst = getvec(1);
- fillst[0] = 1;
- filcnt = 0;
-
- fillst[1] = getvec( FL_SIZE );
- fillst[1][FL_NAME] = concat( getvec(length(fname)/4), fname );
- fillst[1][FL_MODE] = FM_TEXT;
- fillst[1][FL_RAND] = FALSE;
- fillst[1][FL_DISC] = FALSE;
- fillst[1][FL_PERM] = FALSE;
- fillst[1][FL_OVWR] = TRUE;
-
- state = 'S'; /* Start in Send-Init state */
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
-
- repeat { /* Do this as long as necessary */
- eprintf( DBG_STATES, " mesgsw %c %d*n", state, n );
-
- switch( state ) {
- case 'D': /* Data-Send state */
- state = sdata();
- break;
- case 'F': /* File-Send */
- state = sfile(sname);
- break;
- case 'Z': /* End of File */
- state = seof();
- if( state == 'F' ) /* If ready for next file */
- state = 'B'; /* Do Break */
- break;
- case 'S': /* Send Init */
- state = sinit();
- break;
- case 'B': /* Break-Send */
- state = sbreak();
- break;
- case 'C': /* Complete */
- flusheol();
- return(TRUE);
- default: /* Anything else is an error */
- failmsg(llstate); /* Put out an error message */
- if( fd != ERR ) { /* If file left open */
- close(fd); /* Close it */
- fd = ERR; /* Remember it's closed */
- }
-
- flusheol();
- return(FALSE); /* Error return */
- }
-
- llstate = lstate;
- lstate = state; /* Remember last state */
- }
-
- } /* mesgsw */
- /* kermit/s/mesgsw >> End << */
- /* kermit/s/outnam >> Begin << */
- /*
- * OUTNAM -- convert an OUTgoing fileNAMe.
- * This routine converts a local file name to
- * a form recognizable by most other systems.
- *
- * The format of the name is :
- *
- * name.ext
- *
- * Where "name" can be 8 characters long and "ext"
- * can be 3 characters long or not even present.
- * The characters should be uppercase.
- */
-
- outnam( name ) {
- auto i;
-
- uppercase( name );
-
- /*
- * Strip off leading catalogs.
- */
-
- for( i = length(name)-1; i >= 0; --i )
- if( char(name,i) == '/' )
- break;
- if( i >= 0 )
- rep.st( name, 0, "", i+1 );
-
- /*
- * Strip password (if any).
- */
-
- if( (i = any( '$', name )) != -1 )
- lchar( name, i, '*0' );
-
- /*
- * Found a '.'
- */
-
- if( (i = any( '.', name )) >= 0 ) {
- if( i > 8 ) { /* Name is too long */
- movelr( name,8, name,i, length(name)-i+1 );
- i = 8;
- }
- if( length(name)-i > 4 ) /* If extension is too long */
- lchar( name, i+4, '*0' ); /* Truncate it. */
- }
- else {
- if( length(name) > 8 ) /* If name too long .... */
- lchar( name, 8, '*0' ); /* Truncate it. */
- }
-
- return( name );
- } /* outnam */
- /* kermit/s/outnam >> End << */
- /* kermit/s/pkt2str >> Begin << */
- /*
- * PKT2STR -- convert a PacKeT TO a STRing.
- * Packets are simple arrays of characters.
- * Strings are packed four character per word.
- * Control-quoting, 8-bit & repeat prefixes are done.
- */
-
- pkt2str( str, pkt ) {
- extrn quotec, bquote, reptc, dobquo, dorept;
- auto nrep, i, j, len, c, c7, c8;
-
- /*
- * Loop through data.
- */
-
- len = 0;
-
- for( i = 0; (c = pkt[i]) != '*0'; ++i ) {
-
- if( !dorept || c != reptc ) /* Repeat prefix? */
- nrep = 1;
- else {
- nrep = unchar(pkt[++i]); /* Get the count */
- c = pkt[++i]; /* Next char */
- }
-
- if( !dobquo || c != bquote ) /* Eighth-bit quote? */
- c8 = 0;
- else {
- c8 = 128; /* save bit's value */
- c = pkt[++i]; /* Next char */
- }
-
- if( c == quotec ) { /* A quoted char */
- c = pkt[++i]; /* get the next char */
- if( (c7 = mask(c)) >= '?' && c7 <= '_' )
- c = ctl(c); /* Controlify the char */
- }
-
- c |= c8; /* Or in eighth bit */
-
- for( j = 1; j <= nrep; ++j ) /* Put out correct number of chars */
- lchar( str, len++, c );
- } /* for */
-
- lchar( str, len, '*0' );
-
- return( len );
- } /* pkt2str */
- /* kermit/s/pkt2str >> End << */
- /* kermit/s/prhelp >> Begin << */
- /*
- * PRHELP -- PRint a HELP message.
- */
-
- prhelp( cmd, unit ) {
- auto old_unit;
-
- if( nargs() < 2 )
- unit = -4;
-
- old_unit = .write( unit );
-
- printf( "*n" );
-
- if( .abbrv( "Done", cmd ) != -1
- || .abbrv( "Exit", cmd ) != -1 || .abbrv( "Quit", cmd ) != -1 ) {
- printf( "*
- * Done -- Exit KERMIT*n*
- * Exit -- Exit KERMIT*n*
- * Quit -- Exit KERMIT*n*
- * *n*
- * Syntax:*n*
- * Done*n*
- * or Exit*n*
- * or Quit*n*
- * *n*
- * The Done, Exit and Quit commands exit KERMIT.*n*
- * No options are allowed for this command.*n" );
- }
- else if( equal( cmd, "?" ) ) {
- printf( "*
- * ? -- Query the allowed options*n*
- * *n*
- * A ? symbol in place of a command or an option*n*
- * will cause a list of the possible commands or*n*
- * options at that point. To get an explanation*n*
- * of the command/option, use the Help command.*n" );
- }
- else if( .abbrv( "Help", cmd ) != -1 ) {
- printf( "*
- * Help -- Provide Basic Explanations*n*
- * *n*
- * Syntax:*n*
- * Help <command or option>*n*
- * *n*
- * The Help command prints information about the <command>*n*
- * or <option> specified.*n*
- * *n*
- * Commands recognized:*n*
- * ? Done Exit Help Quit*n*
- * Receive SENd SERver SET STatus*n*
- * Options recognized:*n*
- * CWD DeBug Delay Discard Format*n*
- * indeX filename OverWrite Permanent Random*n*
- * SendEOL SendStartofPacket TapeMode*n" );
- }
- else if( .abbrv( "Receive", cmd ) != -1 ) {
- printf( "*
- * Receive -- Receive a file*n*
- * *n*
- * Syntax:*n*
- * Receive [<option>]***n*
- * *n*
- * The Receive command causes GCOS KERMIT to wait for files to*n*
- * be sent from the local KERMIT. The files will be accessed*n*
- * according to the current option settings, unless overridden*n*
- * on the command line.*n*
- * *n*
- * The following options are recognized:*n*
- * CWD DeBug Delay Discard*n*
- * Format OverWrite Permanent Random*n*
- * SendEOL SendStartofPacket TapeMode*n" );
- }
- else if( .abbrv( "SENd", cmd ) != -1 ) {
- printf( "*
- * SENd -- Send a File*n*
- * *n*
- * Syntax:*n*
- * SENd [<filespec>]** [<option>]***n*
- * *n*
- * A <filespec> is either the name of a file to send or*n*
- * *"indeX=filename*" where the file contains KERMIT SENd command*n*
- * options and filespecs.*n*
- * *n*
- * The SENd command causes GCOS KERMIT to send files to*n*
- * the local KERMIT. The files will be sent according to the*n*
- * current option settings, unless overridden on the command*n*
- * line or in an index file. GCOS KERMIT will wait for the*n*
- * number of seconds specified in the Delay option before*n*
- * starting to send the files. This allows you time to escape*n*
- * back to your local KERMIT and type RECEIVE.*n*
- * *n*
- * The following options are recognized:*n*
- * CWD DeBug Delay Discard Format*n*
- * indeX filename OverWrite Permanent Random*n*
- * SendEOL SendStartofPacket TapeMode*n" );
- }
- else if( .abbrv( "SERver", cmd ) != -1 ) {
- printf( "*
- * SERver -- Enter Server Mode*n*
- * *n*
- * Syntax:*n*
- * SERver [<option>]***n*
- * *n*
- * The SERver command causes GCOS KERMIT to enter server mode.*n*
- * While in server mode, GCOS KERMIT will wait for commands*n*
- * from your local KERMIT. When a command is received, it is*n*
- * executed. Server mode is the preferred mode of operation,*n*
- * although not all local KERMITs support it. If your local*n*
- * KERMIT supports server mode, you should use it. The use of*n*
- * server mode is detailed more fully below.*n*
- * *n*
- * The following options are recognized:*n*
- * CWD DeBug Delay Discard*n*
- * Format OverWrite Permanent Random*n*
- * SendEOL SendStartofPacket TapeMode*n" );
- }
- else if( .abbrv( "SET", cmd ) != -1 ) {
- printf( "*
- * SET -- Set KERMIT Options*n*
- * *n*
- * Syntax:*n*
- * SET [<option>]***n*
- * *n*
- * The SET command causes KERMIT to set its options as you*n*
- * specify on the command line. Normally, options given on a*n*
- * command line apply only to that command. A SET command*n*
- * causes them to change until a later SET command is given.*n*
- * *n*
- * The following options are recognized:*n*
- * CWD DeBug Delay Discard*n*
- * Format OverWrite Permanent Random*n*
- * SendEOL SendStartofPacket TapeMode*n" );
- }
- else if( .abbrv( "STatus", cmd ) != -1 ) {
- printf( "*
- * STatus -- Print Options Status*n*
- * *n*
- * Syntax:*n*
- * STatus*n*
- * *n*
- * The STatus command causes GCOS KERMIT to print a list of the*n*
- * current option settings.*n*
- * No options are allowed for this command.*n" );
- }
- else if( .abbrv( "indeX", cmd ) != -1 ) {
- printf( "*
- * indeX=filename*n*
- * causes the file specified to be read and each line*n*
- * treated as options and files for the SENd command.*n*
- * The files named are sent. Index files may be nested.*n*
- * The only options allowed within index files are*n*
- * *"Format=*", +Random, +Discard, -Permanent, +OverWrite.*n*
- * *n*
- * This option may only be used with the SENd command.*n" );
- }
- else if( .abbrv( "Format", cmd ) != -1 ) {
- printf( "*
- * Format=fileformat*n*
- * causes any file transferred in either direction to be*n*
- * treated according to the file format specified. The*n*
- * formats are *"Text*", *"BYtestream*", and *"BItstream*".*n*
- * See the section on file formats in the Writeup. The*n*
- * default is Text.*n*
- * *n*
- * This option may be used with the commands:*n*
- * Receive, SENd, SERver and SET.*n" );
- }
- else if( .abbrv( "DeBug", cmd ) != -1 ) {
- printf( "*
- * DeBug=function*n*
- * specifies how much debugging information is to be*n*
- * written to the debug file *"kerm**dbg*". The default is*n*
- * *"Off*", which means that no debugging information will*n*
- * be written. *"States*" causes the current protocol*n*
- * state to be written when it changes. *"Packets*"*n*
- * causes each packet sent or received to be written.*n*
- * *"All*" causes all possible debug information to be*n*
- * written. This information is rarely useful, unless*n*
- * you suspect your communications line of being noisy*n*
- * and wish to inspect what is being sent.*n*
- * *n*
- * This option may be used with the commands:*n*
- * Receive, SENd, SERver and SET.*n" );
- }
- else if( .abbrv( "Delay", cmd ) != -1 ) {
- printf( "*
- * Delay=nn*n*
- * causes KERMIT to wait nn seconds before sending in-*n*
- * formation when using the SENd command. The default*n*
- * is 10 seconds.*n*
- * *n*
- * This option may be used with the commands:*n*
- * Receive, SENd, SERver and SET.*n" );
- }
- else if( .abbrv( "Random", cmd ) != -1 ) {
- printf( "*
- * -Random*n*
- * +Random*n*
- * causes KERMIT to access the file as random. The*n*
- * default is sequential. For non-text files, +Random*n*
- * must be specified.*n*
- * *n*
- * This option may be used with the commands:*n*
- * Receive, SENd, SERver and SET.*n" );
- }
- else if( .abbrv( "Discard", cmd ) != -1 ) {
- printf( "*
- * -Discard*n*
- * +Discard*n*
- * causes KERMIT to discard an incomplete transmission.*n*
- * If you interrupt the transmission of a file, the file*n*
- * will not be created on GCOS. If -OverWrite is in ef-*n*
- * fect, the previous contents will be unchanged.*n*
- * *n*
- * This option may be used with the commands:*n*
- * Receive, SENd, SERver and SET.*n" );
- }
- else if( .abbrv( "Permanent", cmd ) != -1 ) {
- printf( "*
- * +Permanent*n*
- * -Permanent*n*
- * causes KERMIT to create the file as a permanent file.*n*
- * This is the default. If -permanent is specified,*n*
- * then the usual GCOS access conventions are used, i.e.*n*
- * if there are no slashes or dollar signs in the*n*
- * filename and if the filename is less than or equal to*n*
- * eight characters long, and if a quick access file of*n*
- * the same name does not already exist, the file will*n*
- * be created as temporary.*n*
- * *n*
- * This option may be used with the commands:*n*
- * Receive, SENd, SERver and SET.*n" );
- }
- else if( .abbrv( "TapeMode", cmd ) != -1 ) {
- printf( "*
- * -TapeMode*n*
- * +TapeMode*n*
- * causes KERMIT to use GCOS paper tape mode to read*n*
- * packets. This is the default. At sites with Honey-*n*
- * well's new front end processors (DN8), paper tape*n*
- * mode need not be used if the character delete is set*n*
- * to a non-printing character (usually a backspace or*n*
- * delete). Since GRTS cannot reset the character*n*
- * delete (@), and since KERMIT does indeed transmit @s,*n*
- * paper tape mode must be used to read the input to*n*
- * preserve the @s. This option conflicts with any flow*n*
- * control done by anyone.*n*
- * *n*
- * This option may be used with the commands:*n*
- * Receive, SENd, SERver and SET.*n" );
- }
- else if( .abbrv( "OverWrite", cmd ) != -1 ) {
- printf( "*
- * -OverWrite*n*
- * +OverWrite*n*
- * causes an existing file of the same name to be over-*n*
- * written. The default is -OverWrite, which causes the*n*
- * incomming file to be renamed to avoid conflicts. The*n*
- * file is renamed by appending *"_n*" to the file, where*n*
- * n is the smallest digit not resulting in a clash. If*n*
- * the filename is too long, the underscore will be*n*
- * omitted. If the filename is still too long,*n*
- * characters will be deleted from the end until it*n*
- * fits.*n*
- * *n*
- * This option may be used with the commands:*n*
- * Receive, SENd, SERver and SET.*n" );
- }
- else if( .abbrv( "SendEndOfLine", cmd ) != -1 ) {
- printf( "*
- * SendEndOfLine=nn*n*
- * causes KERMIT to terminate its outgoing packets with*n*
- * the ASCII character whose decimal value is nn. Ex-*n*
- * ample: SendEndOfLine=26 would cause KERMIT to ter-*n*
- * minate its outgoing packets with a control-Z (decimal*n*
- * ASCII value = 26). The default is carriage return*n*
- * (value = 13).*n*
- * *n*
- * This option may be used with the commands:*n*
- * Receive, SENd, SERver and SET.*n" );
- }
- else if( .abbrv( "SendStartofPacket", cmd ) != -1 ) {
- printf( "*
- * SendStartofPacket=nn*n*
- * causes KERMIT to start its outgoing packets with the*n*
- * ASCII character whose decimal value is nn. Example:*n*
- * SendStartofPacket=26 would cause KERMIT to start its*n*
- * outgoing packets with a control-Z (decimal ASCII*n*
- * value = 26). The default is control-A (value = 1).*n*
- * *n*
- * This option may be used with the commands:*n*
- * Receive, SENd, SERver and SET.*n" );
- }
- else if( .abbrv( "ChangeWorkingDirectory", cmd ) != -1 ) {
- printf( "*
- * ChangeWorkingDirectory=catalog*n*
- * causes KERMIT to change its internal working directory*n*
- * to the catalog given. If the catalog begins with a*n*
- * slash (/) it will be appended to the current working*n*
- * directory. If the catalog is null or a question*n*
- * mark (?) is given, the current working catalog will be*n*
- * displayed. The working catalog is where KERMIT*n*
- * creates/accesses files when they start with a slash*n*
- * or contain no slashes (quick access files).*n*
- * *n*
- * This option may be used with the commands:*n*
- * Receive, SENd, SERver and SET.*n" );
- }
- else {
- printf( "%s: Unrecognized command or option.*n", cmd );
- }
-
- printf( "*n" );
-
- .write( old_unit );
-
- } /* prhelp */
- /* kermit/s/prhelp >> End << */
- /* kermit/s/prquery >> Begin << */
- /*
- * PRQUERY -- PRint a response to a QUERY.
- */
-
- prquery( cmd, argno ) {
- extrn remote;
-
- printf( "*n" );
-
- if( argno == 0 ) {
- printf( "*
- * Commands recognized:*n*
- * ? Done Exit Help Quit*n*
- * Receive SENd SERver SET STatus*n" );
- }
- else if( cmd == OP.DONE
- || cmd == OP.EXIT
- || cmd == OP.QUIT
- || cmd == OP.STAT ) {
- printf( " No options are allowed for this command.*n" );
- }
- else if( cmd == OP.RECV || cmd == OP.SERV || cmd == OP.SET ) {
- printf( "*
- * The following options are recognized:*n*
- * CWD DeBug Delay Discard*n*
- * Format OverWrite Permanent Random*n*
- * SendEOL SendStartofPacket TapeMode*n" );
- }
- else if( cmd == OP.SEND ) {
- printf( "*
- * The following options are recognized:*n*
- * CWD DeBug Delay Discard Format*n*
- * indeX filename OverWrite Permanent Random*n*
- * SendEOL SendStartofPacket TapeMode*n" );
- }
- else {
- printf( "Unrecognized query command.*n" );
- }
-
- printf( "*n For information on specific commands/options, type*n" );
- printf( " Help <command or option>*n*n" );
-
- } /* prquery */
- /* kermit/s/prquery >> End << */
- /* kermit/s/prsts >> Begin << */
- /*
- * PRSTS -- PRint the STatuS.
- */
-
- prsts( unit ) {
- extrn curflgs, chktype, debug, delay, retryflg, tapflg, wc;
- extrn eol, stpkt;
- auto old_unit;
-
- if( nargs() < 1 )
- unit = -4;
-
- old_unit = .write( unit );
-
- printf( "*nStatus:*n" );
-
- printf( "Format=" );
- if( curflgs[FL_MODE] == FM_TEXT )
- printf( "Text" );
- else if( curflgs[FL_MODE] == FM_ASA9 )
- printf( "Bytestream" );
- else if( curflgs[FL_MODE] == FM_BITS )
- printf( "Bitstream" );
- printf( "*n" );
-
- printf( "Debug=" );
- if( debug == DBG_OFF )
- printf( "Off " );
- if( debug & DBG_STATES )
- printf( "States " );
- if( debug & DBG_PACKETS )
- printf( "Packets " );
- if( debug & DBG_LOGFILE )
- printf( "Logfile " );
- printf( "*n" );
-
- printf( "Delay=%d*n", delay );
- printf( "%cRandom*n", curflgs[FL_RAND] ? '+' : '-' );
- printf( "%cDiscard*n", curflgs[FL_DISC] ? '+' : '-' );
- printf( "%cPermanent*n", curflgs[FL_PERM] ? '+' : '-' );
- printf( "%cOverWrite*n", curflgs[FL_OVWR] ? '+' : '-' );
- printf( "%cTapeMode*n", tapflg ? '+' : '-' );
- printf( "SendEndOfLine=%d*n", eol );
- printf( "SendStartofPacket=%d*n", stpkt );
- printf( "CWD=%s*n", wc );
-
- printf( "*n" );
-
- .write( old_unit );
- } /* prsts */
- /* kermit/s/prsts >> End << */
- /* kermit/s/put_eof >> Begin << */
- /*
- * PUT_EOF -- PUT an EOF to the file.
- */
-
- put_eof() {
- extrn binfil, fd, flbuf, flidx, flcnt, flseg, flsec;
- auto sts;
-
- if( flidx == 0 )
- return;
-
- if( binfil != FM_TEXT ) {
- if( (sts = write( fd, flbuf, flsec, 320 )) < 0 )
- return( sts );
- flsec += 5;
- flidx = 0;
- return;
- }
-
- flbuf[0] = ((flidx+3)/4) << 18;
- flbuf[0] |= (flidx&03)<<16;
-
- while( flidx & 03 )
- lchar( &flbuf[1], flidx++, 0177 );
-
- if( flseg == 0 ) {
- flbuf[0] |= (01 << 10) | 0600;
- }
- else {
- flbuf[0] |= (02 << 10) | (flseg++);
- flseg = 0;
- }
-
- if( (sts = putrec( fd, flbuf )) < 0 )
- return( sts );
-
- flidx = 0;
-
- return( 0 );
- } /* put_eof */
- /* kermit/s/put_eof >> End << */
- /* kermit/s/put_rec >> Begin << */
- /*
- * PUT_REC -- PUT a physical RECord out to a file.
- */
-
- put_rec( partflag ) {
- extrn fd, binfil, flbuf, flidx, flcnt, flseg, flsec;
- auto sts;
-
- if( binfil != FM_TEXT ) {
- if( (sts = write( fd, flbuf, flsec, 320 )) < 0 )
- return( sts );
- flsec += 5;
- flidx = 0;
- zero( flbuf, 320 );
- return;
- }
-
- if( flidx == 0 ) {
- flbuf[1] = 0177 << 27;
- flidx = 1;
- }
-
- flbuf[0] = ((flidx+3)/4) << 18;
- flbuf[0] |= (flidx&03)<<16;
-
- while( flidx & 03 )
- lchar( &flbuf[1], flidx++, 0177 );
-
- if( flseg == 0 ) {
- flbuf[0] |= 0600;
- if( partflag ) {
- flbuf[0] |= 01 << 10;
- flseg = 1;
- }
- }
- else if( partflag )
- flbuf[0] |= (02 << 10) | (flseg++);
- else {
- flbuf[0] |= (03 << 10) | flseg;
- flseg = 0;
- }
-
- if( (sts = putrec( fd, flbuf )) < 0 )
- return( sts );
-
- zero( flbuf, 320 );
-
- flidx = 0;
-
- return( 0 );
- } /* put_rec */
- /* kermit/s/put_rec >> End << */
- /* kermit/s/putbuf >> Begin << */
- /*
- * PUTBUF -- outPUT a BUFfer of data.
- */
-
- putbuf( line, len ) {
- extrn pad, xonwait, padchar, eolpend;
- auto i;
-
- eprintf( DBG_PACKETS, " spack (raw):%s*n", line );
-
- /*
- * Issue any padding.
- */
-
- for( i = 1; i <= pad; ++i )
- putchar( padchar );
-
- /*
- * Send the packet.
- */
-
- for( i = 0; i < len; ++i )
- putchar( line[i] );
-
- /*
- * Flush the output buffer.
- */
-
- eolpend = TRUE;
- flush();
-
- } /* putbuf */
- /* kermit/s/putbuf >> End << */
- /* kermit/s/putch >> Begin << */
- /*
- * PUTCH -- PUT a CHaracter out to a file.
- * Returns 0 if successful, the negative of
- * the major filesystem status if not.
- */
-
- putch( ch ) {
- extrn binfil, flcrcnt, flbuf, flidx, flcnt;
- auto i, sts;
-
- if( binfil == FM_ASA9 ) {
- if( flidx >= flcnt )
- if( (sts = put_rec( TRUE )) < 0 )
- return( sts );
- lchar( flbuf, flidx++, ch );
- }
- else if( binfil == FM_BITS ) {
- if( flidx >= flcnt )
- if( (sts = put_rec( TRUE )) < 0 )
- return( sts );
- switch( flidx % 9 ) {
- case 0: flbuf[2*(flidx/9)] = ch<<28; break;
- case 1: flbuf[2*(flidx/9)] |= ch<<20; break;
- case 2: flbuf[2*(flidx/9)] |= ch<<12; break;
- case 3: flbuf[2*(flidx/9)] |= ch<<4; break;
- case 4: flbuf[2*(flidx/9)] |= ch>>4;
- flbuf[2*(flidx/9)+1] = (ch&017)<<32; break;
- case 5: flbuf[2*(flidx/9)+1] |= ch<<24; break;
- case 6: flbuf[2*(flidx/9)+1] |= ch<<16; break;
- case 7: flbuf[2*(flidx/9)+1] |= ch<<8; break;
- case 8: flbuf[2*(flidx/9)+1] |= ch; break;
- } /* switch */
- ++flidx;
- }
- else if( ch == '*r' )
- ++flcrcnt;
- else {
- for( i = (ch=='*n')?1:0; i < flcrcnt; ++i ) {
- if( flidx >= flcnt )
- if( (sts = put_rec( TRUE )) < 0 )
- return( sts );
- lchar( &flbuf[1], flidx++, '*r' );
- }
-
- if( flcrcnt > 0 && ch == '*n' ) {
- if( (sts = put_rec( FALSE )) < 0 )
- return( sts );
- }
- else {
- if( flidx >= flcnt )
- if( (sts = put_rec( TRUE )) < 0 )
- return( sts );
- lchar( &flbuf[1], flidx++, ch );
- }
- flcrcnt = 0;
- }
-
- return( 0 );
- } /* putch */
- /* kermit/s/putch >> End << */
- /* kermit/s/quit >> Begin << */
- /*
- * QUIT -- QUIT kermit and logout the session.
- */
-
- quit() {
-
- eprintf( DBG_ALL, "EXIT and logoff*n" );
- putchar( DC1 );
- flush();
-
- sum.up(); /* Close all open files */
-
- sleep( 5 );
- drl.drl( T.DISC_ );
-
- } /* quit */
- /* kermit/s/quit >> End << */
- /* kermit/s/rdata >> Begin << */
- /*
- * RDATA -- Receive DATA.
- */
-
- rdata() {
- extrn n, numtry, oldtry, fd, state, packet, filnam, flsyerr, io.err;
- auto num, len, sts;
-
- if( numtry > MAXTRY ) /* "Abort" if too many tries */
- return( 'm' );
-
- ++numtry;
-
- switch( rpack(&len,&num,packet) ) { /* Get packet */
- case 'D': /* Got Data packet */
- if( num != n ) { /* Right packet ? */
- if( oldtry > MAXTRY ) /* No. Too many tries */
- return( 'm' );
- ++oldtry; /* give up */
- if( num == ((n-1)&63) ) { /* Previous packet again ? */
- spack( 'Y', num, 0, 0 ); /* Yes, re-ACK it */
- numtry = 0; /* Reset try counter */
- return( state ); /* Stay in D, don't write out data! */
- }
- else
- return( 'n' ); /* Sorry! Wrong number. */
- }
-
- /*
- * Got data with the right packet number.
- * Write the data to the file.
- */
-
- if( (sts = bufemp( packet, len )) < 0 ) {
- errmsg( "%s: %s", filnam, io.err[-sts] );
- return( 'a' );
- }
-
- spack( 'Y', n, 0, 0 ); /* Acknowledge the packet */
- oldtry = numtry; /* Reset the try counters */
- numtry = 0; /* ... */
- n = (n+1) & 63; /* Bump the packet number */
- return( 'D' ); /* Remain in data state */
-
- case 'F': /* Got a File Header */
- if( oldtry > MAXTRY ) /* If too many tries, "abort" */
- return( 'm' );
- ++oldtry;
- if( num == ((n-1)&63) ) { /* It was the previous packet */
- spack( 'Y', num, 0, 0 ); /* ACK it again */
- numtry = 0; /* Reset try counter */
- return( state ); /* Stay in data state */
- }
- else
- return( 'n' ); /* Not previous packet, "abort" */
-
- case 'Z': /* End-Of-File */
- if( num != n ) /* Must have right packet number */
- return( 'n' );
- spack( 'Y', n, 0, 0 ); /* OK, ACK it. */
-
- /*
- * Flush possible final CR.
- * Flush file system buffers.
- * Close the file.
- */
-
- if( (sts = bufemp( packet, 0 )) < 0 || (sts = put_eof()) < 0 ) {
- errmsg( "%s: %s", filnam, io.err[-sts] );
- return( 'a' );
- }
- else if( (sts = fclose( fd, FALSE )) < 0 ) {
- errmsg( "%s: %s", filnam, flsyerr[-sts] );
- return( 'a' );
- }
- fd = ERR; /* Remember that file was closed */
- n = (n+1) & 63; /* Bump the packet number */
- return( 'F' ); /* Go back to Receive File state */
-
- case 'c': /* No good packet came */
- spack( 'N', n, 0, 0 ); /* NAK */
- return( state ); /* Keep waiting */
- case 'E': /* Error packet */
- errpkt( packet ); /* print it */
- return( 'a' ); /* Abort */
- default:
- return( 'w' ); /* Some other packet, "abort" */
- }
-
- } /* rdata */
- /* kermit/s/rdata >> End << */
- /* kermit/s/rdcomm >> Begin << */
- /*
- * RDCOMM -- ReaD the COMMunications line.
- * Use paper tape mode to read in input.
- */
-
- rdcomm() {
- extrn fdtap, tpidx, tpcnt, tpeof, tpsect, tpbuf, msghdr, eolpend, eol;
- auto i, psw, tal, drv, eolstr[0];
-
- if( tpeof ) {
- HELL:
- psw = setpsw(0);
- rstpsw(010000000000);
-
- if( eolpend ) {
- eolstr[0] = eol << 27;
- tal = tallyb( eolstr, 0, 1 );
- }
- else
- tal = tallyb( "*n", 0, 1 );
-
- drv = (&tal<<18) | 0100;
- drl.drl(T.TPIN_,&drv<<18);
-
- rstpsw(-1);
- setpsw(psw);
-
- tpsect = 0;
- }
-
- if( nobrks() ) {
- printf( -4, "%s: Break key.*n", msghdr );
- printf( -4, "To exit KERMIT type control-D control-S (^D^S)" );
- flush();
- nobrks( MAX_BRKS );
- goto HELL;
- }
-
- read( fdtap, tpbuf, tpsect++, 64 );
-
- if( (tpbuf[1] & 04) || (!(tpbuf[1] & 02) && (tpbuf[32] & 04)) )
- eprintf( DBG_PACKETS, "Timing error in sector %6o", tpbuf[0] & 0777777 );
-
- if( tpbuf[1] & 02 ) { /* last block */
- tpeof = TRUE;
- tpcnt = tpbuf[1]>>18;
- }
- else {
- tpeof = (tpbuf[32] & 02);
- tpcnt = (tpbuf[1]>>18) + (tpbuf[32]>>18);
-
- copy( &tpbuf[32], &tpbuf[33], 32 );
- }
-
- lchar( &tpbuf[2], tpcnt++, DC3 );
-
- tpidx = 0;
-
- } /* rdcomm */
- /* kermit/s/rdcomm >> End << */
- /* kermit/s/recsw >> Begin << */
- /*
- * RECSW -- RECeive SWitcher.
- *
- * This is the state table switcher for receiving files.
- */
-
- recsw( flags ) {
- extrn n, numtry, fd, srvflg, state, filnam, flsyerr;
- auto lstate, llstate, sts;
-
- if( srvflg == 1 ) /* If in server mode */
- state = 'F'; /* start in F state. */
- else {
- state = 'R'; /* Receive is the start state */
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
- }
-
- repeat { /* Do until done */
- eprintf( DBG_STATES, " recsw %c %d*n", state, n );
-
- switch( state ) {
- case 'D':
- state = rdata(); /* Data receive state */
- break;
- case 'F':
- state = rfile( flags ); /* File receive state */
- break;
- case 'R':
- state = rinit(); /* Send initiate state */
- break;
- case 'C':
- flusheol();
- return( TRUE ); /* Complete state */
- default: /* Anything else is an error */
- failmsg( llstate ); /* Put out an error message */
- if( fd != ERR ) {
- /*
- * If the file was left open,
- * close it with an error status.
- */
- if( (sts = put_eof()) < 0
- || (sts = fclose( fd, TRUE )) < 0 )
- errmsg( "%s: %s", filnam, flsyerr[-sts] );
- fd = ERR; /* Remember it's closed */
- }
- flusheol();
- return( FALSE ); /* Error return */
- }
-
- llstate = lstate; /* Remember last state */
- lstate = state;
- }
-
- } /* recsw */
- /* kermit/s/recsw >> End << */
- /* kermit/s/rfile >> Begin << */
- /*
- * RFILE -- Receive FILE header.
- */
-
- rfile( flags ) {
- extrn n, numtry, oldtry, state, packet, fillst, flsyerr;
- auto num, len, x, g, str;
-
- if( numtry > MAXTRY ) /* If too many tries, "abort" */
- return( 'm' );
- ++numtry;
-
- switch( rpack(&len,&num,packet) ) { /* Get a packet */
- case 'S': /* Send-Init, maybe our ACK lost */
- if( oldtry > MAXTRY ) /* If too many tries, "abort" */
- return( 'm' );
- ++oldtry;
- if( num == ((n-1)&63) ) { /* Previous packet count mod 64? */
- spar( packet ); /* Yes, ACK it again */
- spack( 'Y', num, INIT_SIZ, packet ); /* with our Send-Init parameters */
- numtry = 0; /* Reset try counter */
- return( state ); /* Stay in this state */
- }
- else
- return( 'n' ); /* Not previous packet, "abort" */
-
- case 'Z': /* End of File */
- if( oldtry > MAXTRY )
- return( 'm' );
- ++oldtry;
- if( num == ((n-1)&63) ) { /* Previous packet, mod 64? */
- spack( 'Y', num, 0, 0 ); /* Yes, ACK it again. */
- numtry = 0; /* Reset try counter */
- return( state ); /* Stay in this state */
- }
- else
- return( 'n' ); /* Not previous packet, "abort" */
-
- case 'F': /* File Header */
- if( num != n )
- return( 'n' ); /* which is what we really want */
- /* The packet number must be right */
- str = allocate( MAXLINE _SIZE );
- pkt2str( str, packet );
- getcmd( str, PAR_FIL, flags );
- if( fillst[0] > 1 ) {
- errmsg( "%s: Only one file name allowed.", str );
- return( 'a' );
- }
- else if( fillst[0] < 1 ) {
- errmsg( "%s: No filename given.", str );
- return( 'a' );
- }
- g = getfil(); /* Try to open a new file */
- if( g < 0 ) {
- errmsg( "%s: %s", str, flsyerr[-g] );
- return( 'a' ); /* Give up if can't */
- }
- else if( g == 'a' ) { /* File already exists */
- errmsg( "%s already exists", packet );
- return( 'a' ); /* Give up if can't */
- }
-
- str2pkt( packet, str );
- spack( 'Y', n, length(packet), packet ); /* Acknowledge the file header */
- oldtry = numtry; /* Reset the try counters */
- numtry = 0; /* .... */
- n = (n+1) & 63; /* Bump packet number, mod 64 */
- return( 'D' ); /* Switch to Data state */
-
- case 'B': /* Break transmission (EOT) */
- if( num != n ) /* Need right packet number here */
- return( 'n' );
- spack( 'Y', n, 0, 0 ); /* Say OK */
- return( 'C' ); /* Go to complete state */
-
- case 'c': /* Couldn't get good packet */
- spack( 'N', n, 0, 0 ); /* NAK */
- return( state ); /* Keep Waiting */
- case 'E': /* Error packet */
- errpkt( packet ); /* print it */
- return( 'a' ); /* Abort */
- default:
- return( 'w' ); /* Some other packet, "abort" */
- }
-
- } /* rfile */
- /* kermit/s/rfile >> End << */
- /* kermit/s/rinit >> Begin << */
- /*
- * RINIT -- Receive INITialization.
- */
-
- rinit() {
- extrn n, numtry, oldtry, state, packet;
- auto len, num;
-
- if( numtry > MAXTRY ) /* If too many tries "abort" */
- return( 'm' );
-
- ++numtry;
-
- switch( rpack(&len,&num,packet) ) { /* Get a packet */
- case 'S': /* Send-Init */
- rpar(packet); /* Get the other side's init data */
- spar(packet); /* Fill up packet with my init info */
- spack( 'Y', n, INIT_SIZ, packet ); /* ACK with my parameters */
- oldtry = numtry; /* Save old try count */
- numtry = 0; /* Start a new counter */
- n = (n+1) & 63; /* Bump packet number, mod 64 */
- return( 'F' ); /* Enter file send state */
-
- case 'c': /* Didn't get packet */
- spack( 'N', n, 0, 0 ); /* NAK */
- return( state ); /* Keep waiting */
- case 'E': /* Error packet */
- errpkt( packet ); /* print it */
- return( 'a' ); /* Abort */
- default:
- return( 'w' ); /* Some other packet type, "abort" */
- }
-
- } /* rinit */
- /* kermit/s/rinit >> End << */
- /* kermit/s/rpack >> Begin << */
- /*
- * RPACK -- Read a PACKet.
- */
-
- rpack( len, num, data ) {
- extrn lastpk, chktype;
- auto i, checks, pcheck, ch, type;
-
- while( (ch = getcomm()) != SOH ) /* wait for start of packet */
- if( ch == '*004' )
- error( "I'm getting out of here!" );
-
- /*
- * Got SOH, loop to get a packet.
- */
-
- repeat {
-
- ch = getcomm(); /* Get character */
- if( ch == SOH ) next; /* Resynchronize if SOH */
-
- checks = ch; /* Start the checksum */
- *len = unchar(ch)-3; /* Character count */
-
- ch = getcomm(); /* Get character */
- if( ch == SOH ) next; /* Resynchronize if SOH */
-
- checks += ch; /* Accumulate checksum */
- *num = unchar(ch); /* Packet number */
-
- ch = getcomm(); /* Get character */
- if( ch == SOH ) next; /* Resynchronize if SOH */
-
- checks += ch; /* Accumulate checksum */
- type = ch; /* Packet type */
-
- for( i = 0; i < *len; ++i ) { /* The data itself if any */
- ch = getcomm(); /* Get character */
- if( ch == SOH ) break; /* Resynch if SOH */
-
- checks += ch; /* Accumulate checksum */
- data[i] = ch; /* Put it in the data buffer */
- }
- if( ch == SOH ) next; /* Resynch if SOH */
-
- data[*len] = '*0'; /* Mark end of data */
-
- ch = getcomm(); /* Get character */
- if( ch == SOH ) next; /* Resynchronize if SOH */
-
- pcheck = unchar( ch );
-
- if( type != 'S' && type != 'I' && type != 'R' ) {
- if( chktype >= 2 ) {
- ch = getcomm(); /* Get character */
- if( ch == SOH ) next; /* Resynchronize if SOH */
-
- pcheck = (pcheck<<6) | unchar(ch);
- }
-
- if( chktype >= 3 ) {
- ch = getcomm(); /* Get character */
- if( ch == SOH ) next; /* Resynchronize if SOH */
-
- pcheck = (pcheck<<6) | unchar(ch);
- }
- }
-
- break; /* Got checksum, done */
- } /* repeat */
-
- eprintf( DBG_PACKETS, " rpack: %c %2d '%s'*n", type, *num, data );
-
- checks = chksum(checks,*len,*num,type,data); /* Perform checksum */
- if( checks != pcheck ) { /* Check the checks, fail if bad */
- eprintf( DBG_PACKETS, " rpack: checksum fail: %d/%d*n", pcheck, checks );
- return( lastpk = 'c' ); /* indicate checksum failure */
- }
-
- return( lastpk = type ); /* All OK, return packet type */
-
- } /* rpack */
- /* kermit/s/rpack >> End << */
- /* kermit/s/rpar >> Begin << */
- /*
- * RPAR -- Read PARameters.
- *
- * Get the other side's send-init parameters.
- */
-
- rpar( data ) {
- extrn spsiz, pad, timint, dobquo, dorept;
- extrn padchar, eol, quotec, bquote, reptc, chktype;
-
- dobquo = FALSE; /* default: no eighth-bit quoting */
- dorept = FALSE; /* default: no repeat prefixing */
-
- if( !data[SI_MAXPACK] ) return;
- /* Maximum send packet */
- spsiz = min( MAXPACK, unchar(data[SI_MAXPACK]) );
-
- if( !data[SI_MYTIME] ) return;
- if( unchar(data[SI_MYTIME]) <= 0 ) /* When I should time out on reads */
- timint = MAXTIM;
- else
- timint = min( MAXTIM, max( MINTIM, unchar(data[SI_MYTIME]) ) );
-
- if( !data[SI_MYPAD] ) return;
- pad = unchar(data[SI_MYPAD]); /* Number of pads to send */
-
- if( !data[SI_MYPCHAR] ) return;
- padchar = ctl(data[SI_MYPCHAR]); /* Padding character to send */
-
- if( !data[SI_MYEOL] ) return;
- eol = unchar(data[SI_MYEOL]); /* EOL character I must send */
-
- if( !data[SI_MYQUOTE] ) return;
- quotec = data[SI_MYQUOTE]; /* Incoming data quote character */
-
- if( !data[SI_MYBQUOTE] ) return;
- bquote = data[SI_MYBQUOTE]; /* Incoming binary quote character */
- /*
- * If I have quoting compiled in
- */
- if( (MYBQUOTE >= 33 && MYBQUOTE <= 62)
- || (MYBQUOTE >= 96 && MYBQUOTE <= 126)
- || MYBQUOTE == 'Y' ) {
- if( (bquote >= 33 && bquote <=62) || (bquote >=96 && bquote <= 126) )
- dobquo = TRUE; /* Eighth-bit quoting agreed, use his char */
- else if( bquote == 'Y' ) {
- dobquo = TRUE; /* Eighth-bit quoting agreed */
- bquote = MYBQUOTE; /* Use my char */
- if( MYBQUOTE == 'Y' )
- bquote = '&'; /* Both said 'Y': use '&' */
- }
- }
-
- if( !data[SI_MYCHECKS] ) return;
-
- if( !data[SI_MYREPTC] ) return;
- reptc = data[SI_MYREPTC]; /* Incoming repeat prefix char */
- if( ((reptc >= 33 && reptc <=62)
- || (reptc >=96 && reptc <= 126)) && reptc == MYREPTC )
- dorept = TRUE; /* Our repeat prefixes agree, so use it */
-
- } /* rpar */
- /* kermit/s/rpar >> End << */
- /* kermit/s/rsclash >> Begin << */
- /*
- * RSCLASH -- ReSolve filename CLASH.
- * Rename the filename given, if necessary,
- * so as not to conflict with existing files.
- */
-
- rsclash( fname ) {
- extrn randflg;
- auto len, st, n, fd;
-
- len = length(fname);
- for( st = len-1; st >= 0; --st )
- if( char(fname,st) == '/' )
- break;
-
- n = 0;
- while( n < 10 && (fd = open( fname, randflg ? "rufeb" : "rufe" )) > 0 ) {
- eprintf( DBG_STATES, "File '%s' already exists.*n", fname );
- close( fd );
-
- ++n;
- if( n > 1 )
- lchar( fname, len-1, n + '0' );
- else if( len - st - 1 == 12 )
- lchar( fname, len-1, '1' );
- else if( len - st - 1 == 11 ) {
- concat( fname, fname, "1" );
- ++len;
- }
- else {
- concat( fname, fname, "_1" );
- len += 2;
- }
- }
-
- /*
- * Return TRUE if we have a unique filename,
- * FALSE otherwise.
- */
-
- return( n < 10 );
- } /* rsclash */
- /* kermit/s/rsclash >> End << */
- /* kermit/s/sbreak >> Begin << */
- /*
- * SBREAK -- Send BREAK (eot).
- */
-
- sbreak() {
- extrn n, numtry, state, recpkt, packet;
- auto num, len;
-
- if( numtry > MAXTRY )
- return( 'm' ); /* If too many tries "abort" */
- ++numtry;
-
- spack('B', n, 0, packet ); /* Send a B packet */
- switch( rpack(&len,&num,recpkt) ) { /* What was the reply */
- case 'N': /* NAK, fail */
- if( n != ((num-1)&63) ) /* ...unless for prev. packet. */
- return( state );
- break;
-
- case 'Y': /* ACK */
- if( n != num )
- return( state ); /* If wrong ACK, fail */
- numtry = 0; /* Reset try counter */
- n = (n+1) & 63; /* and bump packet count */
- return( 'C' ); /* Switch state to Complete */
-
- case 'c':
- return(state); /* Receive failure, stay in state B */
- case 'E': /* Error packet */
- errpkt( recpkt ); /* print it */
- return( 'a' ); /* Abort */
- default:
- return( 'w' ); /* Other, "abort" */
- }
-
- } /* sbreak */
- /* kermit/s/sbreak >> End << */
- /* kermit/s/sdata >> Begin << */
- /*
- * SDATA -- Send file DATA.
- */
-
- sdata() {
- extrn size, n, numtry, state, recpkt, packet;
- auto num, len;
-
- if( numtry > MAXTRY ) /* If too many tries, give up */
- return( 'm' );
- ++numtry;
-
- spack( 'D', n, size, packet ); /* Send a D packet */
-
- switch( rpack(&len,&num,recpkt) ) { /* What was the reply */
- case 'N': /* NAK, just stay in this state, */
- if( n != ((num-1)&63) ) /* unless for previous packet. */
- return( state );
-
- case 'Y': /* ACK */
- if( n != num ) /* If wrong ACK, fail */
- return( state );
- numtry = 0; /* Reset try counter */
- n = (n+1) & 63; /* Bump packet count */
- size = bufill(packet); /* Get data from file */
- if( size == 0 ) { /* If EOF set state to that */
- return( 'Z' );
- }
- return( 'D' ); /* Got data, stay in state D */
-
- case 'c': /* Receive failure, stay in D */
- return( state );
- case 'E': /* Error packet */
- errpkt( recpkt ); /* print it */
- return('a'); /* Abort */
- default: /* Anything else "abort" */
- return( 'w' );
- }
-
- } /* sdata */
- /* kermit/s/sdata >> End << */
- /* kermit/s/sendsw >> Begin << */
- /*
- * SENDSW -- SEND SWitcher.
- *
- * Sendsw is the state table switcher for sending
- * files. It loops until either it finishes, or
- * an error is encountered. The routines called by
- * sendsw are responsible for changing the state.
- *
- * sname -- name of file to send (0 -> use args)
- * start -- state to start in -- 'S' or 'F'
- */
-
- sendsw( start ) {
- extrn n, numtry, fd, state;
- auto lstate, llstate;
- auto sname;
-
- sname = 0;
- state = start; /* Use indicated start state (usually 'S') */
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
-
- repeat { /* Do this as long as necessary */
- eprintf( DBG_STATES, " sendsw %c %d*n", state, n );
-
- switch( state ) {
- case 'D': /* Data-Send state */
- state = sdata();
- break;
- case 'F': /* File-Send */
- state = sfile(0);
- break;
- case 'Z': /* End of File */
- state = seof();
- if( state == 'F' && sname ) /* If ready for next file */
- state = 'B'; /* Do Break */
- break;
- case 'S': /* Send Init */
- state = sinit();
- break;
- case 'B': /* Break-Send */
- state = sbreak();
- break;
- case 'C': /* Complete */
- flusheol();
- return(TRUE);
- default: /* Anything else is an error */
- failmsg(llstate); /* Put out an error message */
- if( fd != ERR ) { /* If file left open */
- close(fd); /* Close it */
- fd = ERR; /* Remember it's closed */
- }
-
- flusheol();
- return(FALSE); /* Error return */
- }
-
- llstate = lstate;
- lstate = state; /* Remember last state */
- }
-
- } /* sendsw */
- /* kermit/s/sendsw >> End << */
- /* kermit/s/seof >> Begin << */
- /*
- * SEOF -- Send End Of File.
- */
-
- seof() {
- extrn n, numtry, fd, state, recpkt, packet;
- auto num, len;
-
- if( numtry > MAXTRY ) /* If too many tries, give up */
- return( 'm' );
-
- ++numtry;
-
- spack( 'Z', n, 0, packet ); /* Send a Z packet */
-
- switch( rpack(&len,&num,recpkt) ) { /* What was the reply ? */
- case 'B': /* NAK, fail */
- if( n != ((num-1)&63) ) /* unless for previous packet */
- return(state);
-
- case 'Y': /* ACK */
- if( n != num ) /* If wrong ACK, hold out */
- return( state );
- numtry = 0; /* Reset try counter */
- n = (n+1) & 63; /* Bump packet count */
- close(fd); /* Close the input file */
- fd = ERR; /* and flag that we did */
- return( 'F' ); /* Go to file header state */
-
- case 'c': /* Receive failure, stay in state Z */
- return( state );
- case 'E': /* Error packet */
- errpkt( recpkt ); /* print it */
- return( 'a' ); /* Abort */
- default: /* Something else, "abort" */
- return( 'w' );
- }
-
- } /* seof */
- /* kermit/s/seof >> End << */
- /* kermit/s/server >> Begin << */
- /*
- * SERVER -- process SERVER mode.
- *
- * This is the state controller for the server mode of operation.
- */
-
- server( flags ) {
- extrn n, numtry, oldtry, fd, filnam, recpkt, packet;
- auto len, num, junk, timeos, typ;
-
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
- timeos = 0; /* No timeouts seen yet */
-
- repeat { /* Do until told to quit */
- typ = rpack( &len, &num, packet ); /* Get a packet */
- eprintf( DBG_STATES, "*nServer %c*n", typ );
-
- switch( typ ) {
- case 'S': /* The other side wants to initialize */
- case 'I':
- rpar(packet); /* Get other side's initial parameters */
- spar(packet); /* Get my initial parameters */
- spack( 'Y', n, INIT_SIZ, packet ); /* Send ACK with my init parameters */
- oldtry = numtry; /* Reset try counters */
- numtry = 0; /* .... */
- if( typ == 'S' ) { /* If this was a send-init packet */
- n = (n+1) & 63; /* Increment packet count */
- recsw( flags ); /* Go to receive state to receive file */
- }
- n = 0; /* Reset packet count */
- break;
-
- case 'R': /* The other side wants to receive */
- pkt2str( filnam, packet ); /* To let packet array be reused */
- getcmd( filnam, PAR_FIL, flags );
- sendsw( 'S' ); /* Send the requested file */
- n = 0;
- break;
-
- case 'G': /* Other side is sending a command */
- if( !generic( num, packet[0], &packet[1], flags ) ) {
- flusheol();
- return;
- }
- n = 0;
- break;
-
- case 'X': /* Valid, but unimplemented */
- errmsg( "Text headers are not implemented." );
- break;
-
- case 'C':
- errmsg( "Host commands are not implemented." );
- break;
-
- case 'K':
- errmsg( "Remote Kermit commands are not yet implemented." );
- break;
-
- case 'N': /* NAK: ignore it (some confusion) */
- break;
-
- case 'a': /* EOF on line: abort */
- flusheol();
- return( 'a' );
-
- case 'c': /* checksum err: */
- spack( 'N', n, 0, 0 ); /* NAK it */
- n = 0;
- break;
-
- case 't': /* timeout */
- timeos = (timeos+1) & 63; /* increment timeout counter */
- if( timeos == 0 ) /* If it rolls over (every fifth) */
- spack( 'N', n, 0, 0 ); /* send out a NAK, just to keep line active */
- n = 0;
- break;
-
- case 'E': /* Error packet */
- errpkt( recpkt ); /* print it */
- break;
-
- default: /* Anything else, reset packet count, retry */
- /* Send an error message */
- errmsg( "%c: not a valid Kermit server command", typ );
- n = 0; /* Reset counter */
- }
-
- if( fd != ERR ) { /* If a file was left open (xfer aborted) */
- close( fd ); /* Close it */
- fd = ERR; /* Remember closure */
- }
- }
-
- } /* server */
- /* kermit/s/server >> End << */
- /* kermit/s/sfile >> Begin << */
- /*
- * SFILE -- Send FILE header.
- *
- * sname = 0 if the default filename is to be sent,
- * the filename to send otherwise.
- */
-
- sfile( sname ) {
- extrn size, n, numtry, remote, state, filnam, recpkt, packet;
- auto num, len, g, str;
-
- g = gnxtfl(); /* Open the file to be sent */
- if( g != 'F' ) /* 'F' => OK */
- return( g ); /* abort or break states */
-
- if( numtry > MAXTRY ) /* If too many tries, give up */
- return( 'm' );
- ++numtry;
-
- if( sname )
- concat( filnam, sname );
- len = str2pkt( packet, filnam );
- spack( 'F', n, len, packet ); /* Send an F packet */
- switch( rpack(&len,&num,recpkt) ) { /* What was the reply ? */
- case 'N': /* NAK, just stay in this state */
- if( n != ((num-1)&63) ) /* unless NAK for next packet */
- return( state );
-
- case 'Y': /* ACK */
- if( n != num ) /* If wrong ACK, stay in F state */
- return( state );
- if( len > 0 && !remote ) { /* If the remote filename was returned */
- str = allocate( MAXLINE _SIZE );
- pkt2str( str, recpkt );
- errmsg( "file being saved as %s", str ); /* print it out */
- }
- numtry = 0; /* Reset try counter */
- n = (n+1) & 63; /* Bump packet count */
- size = bufill(packet); /* Get first data from file */
- return('D'); /* Switch to state D */
-
- case 'c': /* Receive failure, stay in F state */
- case 't':
- return( state );
- case 'E': /* Error packet */
- errpkt( recpkt ); /* print it */
- return( 'a' ); /* Abort */
- default: /* Something else, just "abort" */
- return( 'w' );
- }
-
- } /* sfile */
- /* kermit/s/sfile >> End << */
- /* kermit/s/sinit >> Begin << */
- /*
- * SINIT -- Send INITiate.
- *
- * Send my parameters, get the other side's back.
- *
- * The 10 second wait before sending the first packet gives
- * the user time to get back to his local Kermit and set it
- * to receive.
- */
-
- sinit() {
- extrn n, numtry, remote, sflg, delay;
- extrn state, eol, quotec, recpkt, packet;
- auto num, len;
-
- if( numtry > MAXTRY ) /* If too many tries, give up */
- return( 'm' );
- ++numtry;
-
- if( sflg && remote ) /* If in send only (not server) mode */
- sleep( delay ); /* Wait delay seconds */
-
- spar( packet ); /* Fill packet with init info */
- spack( 'S', n, INIT_SIZ, packet ); /* Send an S packet */
- switch( rpack(&len,&num,recpkt) ) { /* What was reply ? */
- case 'N': /* NAK */
- return( state );
-
- case 'Y': /* ACK */
- if( n != num ) /* If wrong ACK, stay in S state */
- return( state );
- rpar( recpkt ); /* Get other sides init info */
- if( eol == 0 ) /* Check and set defaults */
- eol = CR;
- if( quotec == 0 ) /* Control-prefix quote */
- quotec = '#';
- numtry = 0; /* Reset try counter */
- n = (n + 1) & 63; /* Bump packet count, mod 64 */
-
- return( 'F' ); /* Go to file header state */
-
- case 'c': /* Receive failure, stay in S state */
- case 't':
- return( state );
- case 'E': /* Error packet */
- errpkt( recpkt ); /* print it */
- return( 'a' ); /* Abort */
- default: /* Anything else just abort */
- return( 'w' );
- }
-
- } /* sinit */
- /* kermit/s/sinit >> End << */
- /* kermit/s/spack >> Begin << */
- /*
- * SPACK -- Send a PACKet.
- *
- * If no data is to be sent, data can be passed a zero.
- */
-
- spack( type, num, len, data ) {
- extrn pad, padchar, xonwait, chktype;
- auto i, c, checks, bufptr, buffer[100];
-
- data[len] = '*0'; /* just to be sure */
-
- if( data ) {
- eprintf( DBG_PACKETS, " spack: %c %2d '", type, num );
- for( i = 0; (c = data[i]) != '*0'; ++i )
- eprintf( DBG_PACKETS, "%c", data[i] );
- eprintf( DBG_PACKETS, "'*n" );
- }
- else
- eprintf( DBG_PACKETS, " spack: %c %2d*n", type, num );
-
- bufptr = 0; /* Initialize buffer pointer */
-
- buffer[bufptr++] = SOH; /* Packet marker, ASCII 1 (SOH) */
- checks = tochar(len+3); /* Initialize the checksum */
- buffer[bufptr++] = tochar(len+3); /* Send the character count */
- checks += tochar(num); /* Accumulate checksum */
- buffer[bufptr++] = tochar(num); /* Packet number */
- checks += type; /* Accumulate checksum */
- buffer[bufptr++] = type; /* Packet type */
-
- for( i = 0; i < len; ++i ) { /* Loop for all data characters */
- buffer[bufptr++] = data[i]; /* Get a character */
- checks += data[i]; /* Accumulate checksum */
- }
-
- /*
- * Put the checksum in the packet.
- */
-
- checks = chksum(checks,len,num,type,data); /* Perform checksum */
-
- if( type != 'S' && type != 'I' && type != 'R' ) {
- if( chktype >= 3 )
- buffer[bufptr++] = tochar( (checks>>12) & 017 );
- if( chktype >= 2 )
- buffer[bufptr++] = tochar( (checks>>6) & 077 );
- }
- buffer[bufptr++] = tochar( checks & 077 );
-
- buffer[bufptr] = '*0'; /* Properly terminate packet */
-
- if( xonwait ) { /* Now wait for DC1 (XON) 'prompt' character */
- /*
- while( (c = getchar()) != DC1 && c != SOH )
- */
- ;
- }
-
- putbuf( buffer, bufptr ); /* Send the packet */
-
- } /* spack */
- /* kermit/s/spack >> End << */
- /* kermit/s/spar >> Begin << */
- /*
- * SPAR -- Set the PARameters.
- *
- * Fill the data array with my send-init parameters
- * Different machines may require different parameter definitions.
- */
-
- spar( data ) {
- extrn chktype, tapflg;
-
- data[SI_MAXPACK] = tochar(MAXPACK); /* Biggest packet I can receive */
- data[SI_MYTIME] = tochar(MYTIME); /* When I want to be timed out */
- data[SI_MYPAD] = tochar(0); /* How much padding I need */
- data[SI_MYPCHAR] = ctl(MYPCHAR); /* Padding character I want */
- if( tapflg )
- data[SI_MYEOL] = tochar(MYEOL); /* End of Line character I want */
- else
- data[SI_MYEOL] = tochar( CR );
- data[SI_MYQUOTE] = MYQUOTE; /* Control-Quote character I send */
- data[SI_MYBQUOTE] = MYBQUOTE; /* Binary-Quote character I send */
- data[SI_MYCHECK] = chktype + '0'; /* My preferred type of checksum */
- data[SI_MYREPTC] = MYREPTC; /* Repeat-Quote character I send */
- data[SI_MYCAPS] = tochar(MYCAPS); /* My capabilities mask */
- data[SI_MYSIZE] = '*0'; /* in case this gets printed */
-
- } /* spar */
- /* kermit/s/spar >> End << */
- /* kermit/s/str2pkt >> Begin << */
- /*
- * STR2PKT -- convert a STRing TO a PacKeT.
- * Strings are packed four character per word.
- * Packets are simple arrays of characters.
- */
-
- str2pkt( pkt, str ) {
- auto i;
-
- for( i = 0; (pkt[i] = char(str,i)) != '*0'; ++i )
- ;
-
- return( i );
- } /* str2pkt */
- /* kermit/s/str2pkt >> End << */
- /* kermit/s/tochar >> Begin << */
- /*
- * TOCHAR -- convert a number TO a CHARacter.
- */
-
- tochar( ch ) {
-
- return( ch + ' ' );
- } /* tochar */
- /* kermit/s/tochar >> End << */
- /* kermit/s/unchar >> Begin << */
- /*
- * UNCHAR -- UNdo the effect of toCHAR.
- */
-
- unchar( ch ) {
-
- return( ch - ' ' );
- } /* unchar */
- /* kermit/s/unchar >> End << */
- /* kermit/s/ungtch >> Begin << */
- /*
- * UNGTCH -- UN-GeT a CHaracter.
- * Put a character from a file back into the input stream.
- */
-
- ungtch( ch ) {
- extrn flunbuf;
-
- return( flunbuf[ ++flunbuf[0] ] = ch );
- } /* ungtch */
- /* kermit/s/ungtch >> End << */
- /* kermit/s/wdfile >> Begin << */
- /*
- * WDFILE -- prepend Working Directory to a FILE if necessary.
- */
-
- wdfile( fname, prmflg ) {
- extrn wc;
-
- if( prmflg && any( '/', fname ) == -1 )
- rep.st( fname, 0, "/", 0 );
-
- if( char( fname, 0 ) == '/' )
- rep.st( fname, 0, wc, 0 );
-
- } /* wdfile */
- /* kermit/s/wdfile >> End << */
- /* kermit/s/b_lib/rep.st.b >> Begin << */
- #Title h6600g8.196 rep.st,Replace substring
- #lbl btnw
- #ttldat 091482
- #Copyright (c) 1982 by the University of Waterloo
-
- rep.st(str, start, newstr, leng) {
- auto mover, newleng;
- extrn .mlr, .mrl;
-
- if (.nargs() < 4)
- leng = .lengt(str) - start;;
- /*
- * The #%*@ people at Waterloo got the conditions
- * on the next line backwards!!!!!
- */
- mover = leng < (newleng = .lengt(newstr)) ? .mrl : .mlr;
- mover(str, start + newleng, str, start + leng,
- .lengt(str) - start - leng + 1);
- .mlr(str, start, newstr, 0, newleng);
- }
- /* kermit/s/b_lib/rep.st.b >> End << */
-